|
|
| Посл.отвђт | Сообщен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 в двоичной системе эквивалентно сдвигу на разряд в сторону точки с заполнением младшего разряда нулем. ОК. Проверим. |
|
|
Дата: Май 22, 2004 01:31:30 Black_mirror Edmond Почему топик умер??? Мне бы float (не double) в строку перевести... S.O.S! |
|
|
Дата: Май 22, 2004 20:26:38 Quantum ;destroy: edx,ecx and two FPU-registers
;return: eax - end of string
float_to_str:;(str +4,float +8)
xchg edi,[esp+4]
mov edx,[esp+8]
shl edx,1
fld dword [esp+8]
mov al,'+'
jnc .positive
mov al,'-'
fchs
.positive:
stosb
cmp edx,0ff000000h
mov eax,'INF'
jz .special
mov eax,'NAN'
ja .special
mov eax,4D104D43h ;lg(2)
shr edx,24
mul edx
sub eax,0EE0606B9h ;126*lg(2) = 25.EE0606B9
sbb edx,25h+1
fmul [.pow+edx*4+4]
fld1
fcomp
fstsw ax
sahf
ja .noscale
inc edx
fidiv [.i10]
.noscale:
fild [.i31]
fxch st1
fscale
fistp dword [esp+8]
fstp st0
mov eax,[esp+8]
push edx
add eax,eax
add eax,06Eh;эмперическая константа
jnc .q
mov eax,-1
.q:
mul [.i10]
add edx,'0.'
mov [edi],edx
inc edi
mov ecx,6
inc edi
.outfrac:
mul [.i10]
add dl,'0'
mov [edi],dl
inc edi
loop .outfrac
mov al,'E'
stosb
pop edx
test edx,edx
mov al,'+'
jns .epositive
mov al,'-'
neg edx
.epositive:
stosb
xchg eax,edx
aam 10
xchg al,ah
or ax,'00'
stosw
mov byte [edi],0
.exit:
mov eax,edi
mov edi,[esp+4]
ret 8
.special:
stosd
dec edi
jmp .exit
.i10 dd 10
.i31 dd 31
dd 7E967699h,7CF0BDC2h
dd 7B4097CEh,799A130Ch,77F684DFh,76453719h
dd 749DC5AEh,72FC6F7Ch,7149F2CAh,6FA18F08h
dd 6E013F39h,6C4ECB8Fh,6AA56FA6h,69045951h
dd 6753C21Ch,65A96816h,64078678h,6258D727h
dd 60AD78ECh,5F0AC723h,5D5E0B6Bh,5BB1A2BCh
dd 5A0E1BCAh,58635FA9h,56B5E621h,551184E7h
dd 5368D4A5h,51BA43B7h,501502F9h,4E6E6B28h
dd 4CBEBC20h,4B189680h,49742400h,47C35000h
dd 461C4000h,447A0000h,42C80000h,41200000h
.pow dd 3F800000h,3DCCCCCDh,3C23D70Ah,3A83126Fh
dd 38D1B717h,3727C5ACh,358637BDh,33D6BF95h
dd 322BCC77h,3089705Fh,2EDBE6FFh,2D2FEBFFh
dd 2B8CBCCCh,29E12E13h,283424DCh,26901D7Dh
dd 24E69595h,233877AAh,219392EFh,1FEC1E4Ah
dd 1E3CE508h,1C971DA0h,1AF1C901h,19416D9Ah
dd 179ABE15h,15F79688h,14461206h,129E74D2h
dd 10FD87B6h,0F4AD2F8h,0DA24260h,0C01CEB3h
dd 0A4FB11Fh,08A6274Ch,0704EC3Dh,0554AD2Eh
dd 03AA2425h,02081CEAh,006CE3EEh
На Атлон 1,6 одно преобразование выполняется за 150 тактов. Ошибка округления вроде составляет не более 2х единиц последнего разряда. Но использовать это будете на свой страх и риск 8) |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.084 |