· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.A&O —› -= Float_to_Str =- (алгоритм 5)

<< . 1 . 2 . 3 . >>

Посл.отвђт Сообщен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)

<< . 1 . 2 . 3 . >>


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.084