|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Сен 17, 2003 16:26:47 Black_mirror Если процедура _exp10 использует функцию fx2m1 Там всё ОК. |
|
|
Дата: Сен 17, 2003 16:49:16 Black_mirror Спасибо!!! Но это всё ещё нужно будет менять :))В самом старшем бите находится знак числа, а не экспоненты! можно заменить на jle @F Упппсс :))) Умница!!!! Можно обойтись без умножения 96и-битного числа: Если привести мантисту к диапазону [1..10) то сдвигать ее придется не в право, а в лево. После первого сдвига мы получим целую часть в самом старшем слове и дробную в оставшихся 64х битах. Умножая в цикле дробную часть на 10 мы получим оставшиеся цифры. Меня сейчас волнует немного другое .. ТОЧНОСТЬ. А как быть с периодическими дробями? Думаешь цифры закончатся после умножения на 2^64 ? Нет, не закончатся. Но и не должны они закончится. Но выводит больше 20 цифр смысла все равно нет. У меня даже 20я цифра мусор. Нужно придумать как это правильно округлить. А вот в этом ГОСПОДА и вся загвостка.. Но я могу утверждать, что этот алгоритм имеет единственный шанс на абсолютную точность результата... Ибо в нём не теряются биты... (Почти) |
|
|
Дата: Сен 17, 2003 17:16:16 Смутно припоминаю один из университетских курсов про представление данных в вычислительных машинах... там кажется говорилось что не все 10чные дроби могут быть представлены конечной двоичной и наоборот.... вот вам и проблемы округления :) |
|
|
Дата: Сен 17, 2003 17:55:30 Смутно припоминаю один из университетских курсов про представление данных в вычислительных машинах... там кажется говорилось что не все 10чные дроби могут быть представлены конечной двоичной и наоборот.... вот вам и проблемы округления :) Объясняю тонкость бытия. Нужно создать таки две функции Str_to_Float/Float_to_Str Чтобы они давали одинаковый результат. |
|
|
Дата: Сен 17, 2003 18:02:34 Edmond а если подсмотреть в msvcrt?? :) |
|
|
Дата: Сен 17, 2003 18:10:37 DaemoniacaL Ааа, давайте. Только плиз ИСХОДНИКИ В СТУДИЮ!!! (Пусть дизассемблированные) |
|
|
Дата: Сен 17, 2003 19:38:25 Edmond Нужно создать таки две функции Str_to_Float/Float_to_Str Чтобы они давали одинаковый результат Можно любое двоичное число абсолютно точно перевести в десятичное представление. Но не всякое десятичное число можно преобразовать в двоичное. Проблемма в том, что 1/5 можно представить только ввиде двоичной периодической дроби, а при возведении ее в степень, длина периода только увеличивается, и может составлять величину порядка (1/5)^n цифр, где n - количество цифр после точки в исходном числе. По поводу точности: Точность long double 64 бита, эти 64 бита мы только умножаем на 10, поэтому никаких битов мы не потеряем если правильно выполним округление. Основные потери происходят при возведении 10 в степень и делении или умножении на нее исходного числа. Алгоритм который выполнет преобразование long double в строку абсолютно точно, должем перевести его в формат с фиксированной точкой в котором 16 тысяч бит до запятой и столько же после, а затем последовательными делениями целой части на 10 найдет цифры целой части, и последовательными умножениями дробной части на 10 найдет все цифры дробной части. |
|
|
Дата: Сен 17, 2003 22:39:13 · Поправил: Fixer По поводу точности Вроде это где-то обсуждалось здесь. DaemoniacaL Любая библиотека (несмотря на свою неимоверную крутизну) все равно будет давать погрешность в представлении чисел (в силу двоичной их природы, ведь ты на вход этих функций запихиваешь двоичное число). |
|
|
Дата: Сен 19, 2003 14:30:15 Fixer Вроде это где-то обсуждалось здесь. И не доопсуждалось :))) ОК, после выходных я выпущу бету :)) |
|
|
Дата: Сен 20, 2003 09:58:31
;абсолютно точное преобразование long_double в строку
long_double_to_str:;(str +4, long_double +8, unused_word +18)
;размер строки должен быть 1+1+1+16383+63+1 байт
;результат:
;в str - символьное представление числа
;eax указывает на (последний записанный символ+1)
push ebp
push esi
push edi ;+12
mov edi,[12+esp+4]
;выделяем память, чтобы преобразовать lond_double в fixed_point_16416.16448
mov ecx,4108/4
.alloc:
push 0 ;+4120
loop .alloc
mov edx,[4120+esp+8+8] ;exponent
test dx,dx
jns .no_sign
mov al,'-'
stosb
.no_sign:
;вычисляем на сколько нужно сдвинуть мантисту и куда ее записать
and edx,7fffh
lea ecx,[edx+2]
add edx,2
and ecx,31
and edx,-32
shr edx,3
;сдвиг и запись
xor eax,eax
mov ebx,[4120+esp+8+4]
shld eax,ebx,cl
mov [esp+edx+8],eax
mov eax,[4120+esp+8]
shld ebx,eax,cl
mov [esp+edx+4],ebx
shl eax,cl
mov [esp+edx],eax
lea ebp,[esp+2056]
;преобразование целой части
mov esi,2052
xor eax,eax
push -'0'
.l0: ;отбрасывание ведущих нулей
sub esi,4
js .out_zero
.l1:
xor eax,eax
cmp dword [ebp+esi],eax
jz .l0
mov ecx,esi
xor edx,edx
.l2: ;делим целую часть на 10
mov eax,[ebp+ecx]
div [.c10]
mov [ebp+ecx],eax
sub ecx,4
jns .l2
push edx ;сохраняем цифру
or eax,esi
jnz .l1 ;если целая часть не ноль, то делим снова
.l4: ;вывод цифр
pop eax
.out_zero:
add al,'0'
stosb
jnz .l4
dec edi
.out_pt:
mov al,'.'
stosb
;преобразование дробной части
mov esi,-2060
.l6: ;отбрасывание завершающих нулей
add esi,4
jns .exit
.l8:
cmp dword [ebp+esi],0
jz .l6
xor ebx,ebx
mov ecx,esi
.l7: ;умножаем дробную часть на 10
mov eax,[ebp+ecx]
mul [.c10]
add eax,ebx
adc edx,0
mov [ebp+ecx],eax
mov ebx,edx
add ecx,4
js .l7
or eax,esi
lea eax,[edx+'0'] ;выводим цифру
stosb
jnz .l8 ;если дробная часть не ноль, то умножаем снова
.exit:
cmp al,'.'
jnz .l9
dec edi
.l9:
mov byte [edi],0
add esp,4108 ;+12
xchg eax,edi
pop edi
pop esi
pop ebp ;+0
ret 16
.c10 dd 10
|
|
|
Дата: Сен 20, 2003 12:03:16 ;абсолютно точное преобразование long_double в строку Это как? :)))))) Абсолютно точное не бывает :)) |
|
|
Дата: Сен 20, 2003 22:45:33 Edmond Преобразовать число с плавающей точкой в число с фиксированной точкой без потерь можно. Затем можно преобразовать целую часть в строку. Далее если мы будем умножать дробную часть на 10 то в конце концов дробная часть обнулится, так как один из множителей десяти двойка, а умножение на 2 в двоичной системе эквивалентно сдвигу на разряд в сторону точки с заполнением младшего разряда нулем. По моему преобразование выполняется абсолютно точно. |
|
|
Дата: Сен 22, 2003 10:43:12 Black_mirror Преобразовать число с плавающей точкой в число с фиксированной точкой без потерь можно. Логично. Затем можно преобразовать целую часть в строку. Далее если мы будем умножать дробную часть на 10 то в конце концов дробная часть обнулится, так как один из множителей десяти двойка, а умножение на 2 в двоичной системе эквивалентно сдвигу на разряд в сторону точки с заполнением младшего разряда нулем. ОК. Проверим. |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.067 |