Float2Str

Тема в разделе "WASM.A&O", создана пользователем murder, 30 окт 2009.

  1. murder

    murder Member

    Публикаций:
    0
    Регистрация:
    3 июн 2007
    Сообщения:
    628
    Вот написал процедуру для конвертации из single precision в ASCII без использования FPU. Как ещё можно оптимизировать этот код?
    Код (Text):
    1. procedure float2str(x: single; s: PChar);stdcall;assembler;
    2. asm
    3.   push  ebx
    4.   push  edi
    5.   mov   edi,[s]
    6.   mov   edx,[x]
    7.   mov   ecx,edx
    8.   shr   ecx,23
    9.  
    10.   mov   byte[edi],'-'
    11.   movzx eax,ch
    12.   mov   byte[edi+eax],'0'
    13.   lea   edi,[edi+eax+1]
    14.  
    15.   and   edx,$7FFFFF
    16.   or    edx,$800000                 //мантисса
    17.   shl   edx,8
    18.   movzx ecx,cl
    19.   xor   eax,eax
    20.   sub   ecx,126                     //экспонента
    21.  
    22.   jl @noint
    23.       shld   eax,edx,cl             //целая часть
    24.       shl    edx,cl                 //дробная часть
    25.       push   edx
    26.       push   esi
    27.       mov    ebx,429496730
    28.       mov    esi,esp
    29.       @2:mov  ecx,eax
    30.          mul  ebx
    31.          dec  esi
    32.          sub  ecx,edx
    33.          lea  eax,[edx*8+edx-'0']
    34.          sub  ecx,eax
    35.          mov  eax,edx
    36.          mov  [esi],cl
    37.          test edx,edx
    38.       jne @2
    39.       movups xmm0,[esi]
    40.       movups [edi-1],xmm0
    41.       lea    edi,[edi+esp-1]
    42.       sub    edi,esi
    43.       pop    esi
    44.       pop    edx
    45.       xor    ecx,ecx
    46.   @noint:
    47.  
    48.   test  edx,edx
    49.   je @nofloat
    50.       neg ecx
    51.       shr edx,cl
    52.       mov ebx,10
    53.       mov eax,edx
    54.       mov byte[edi],'.'
    55.       @1:mul  ebx
    56.          inc  edi
    57.          add  edx,'0'
    58.          test eax,eax
    59.          mov  [edi],dl
    60.       jne @1
    61.       inc edi
    62.   @nofloat:
    63.   stosb                             //завершающий ноль
    64.   pop   edi
    65.   pop   ebx
    66. end;
     
  2. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    murder
    А как же денормализованные числа? Для них добавлять единицу совсем не нужно.
    на мой взгляд это очень сомнительная конструкция, будет ли она работать при cl>31?!
    А как же всякие исключения?
    Если не использовать FPU, то какой смысл тянуть SSE из-за двух команд?

    А всякие NAN и INF данной процедурой в принципе не выводятся?!
     
  3. murder

    murder Member

    Публикаций:
    0
    Регистрация:
    3 июн 2007
    Сообщения:
    628
    1) Не понял. На сколько я знаю все числа в формате с одинарной точностью должны быть нормализованы. Поясни.

    2) shld при cl>31 действительно не работает (воспринимаются только младшие 5 бит), но это не важно так как числа, большие чем 2^31 всё равно не могут быть нормально представлены в этом формате (по крайней мере не все). Да и к тому же тогда придётся реализовывать конвертацию 64 битных чисел, а это уже не так красиво.

    3) Про исключения тоже не совсем понятно. Там ведь в стек помещается не более 10 байт - это не так уж и много.

    4) movups мне и самому не нравится, но смотрится очень уж изящно. В общем-то проблема в самом алгоритме, а не в реализации. Было-бы не плохо если бы число конвертировалось в прямом порядке, а не в обратном. В мануалах от AMD берётся обратное значение числа, а затем конвертируется при помощи умножения на 10 (также как дробная часть в этой процедуре). Попробую прикрутить этот метод.

    5) Про NAN и INF я просто забыл. Обязательно добавлю.

    Мне кажется можно избавиться от умножения на 10, но ничего путного придумать не могу.
     
  4. murder

    murder Member

    Публикаций:
    0
    Регистрация:
    3 июн 2007
    Сообщения:
    628
    Про денормализованные числа прочитал. Теперь всё понятно. Не знаю стоит ли усложнять программу ради чисел с порядком меньше -126, это ведь практически ноль. В общем если получится сделать это изящно, то добавлю поддержку денормализованых.
     
  5. murder

    murder Member

    Публикаций:
    0
    Регистрация:
    3 июн 2007
    Сообщения:
    628
    Добавил поддержку NaN и INF. вот так это выглядит
    Код (Text):
    1.   mov   byte[edi],'-'
    2.   movzx eax,ch
    3.   add   edi,eax
    4.   mov   [edi],'FNI'
    5.   mov   ebx,'NaNs'
    6.   and   edx,$7FFFFF
    7.   cmove ebx,[edi]
    8.   mov   eax,edx
    9.   and   eax,$00400000
    10.   mov   [edi+4],al
    11.   shr   eax,21
    12.   sub   ebx,eax
    13.   mov   [edi],ebx
    14.   cmp   cl,255
    15.   je    @exit
    Обнаружилась ещё одна особенность
    Код (Text):
    1. shr edx,cl
    Так у меня выделяется дробная часть. Тут очевидно, что теряются биты и опять таки при cl>31 будет неправильно работать.

    Вопрос такой: как узнать количество лидирующих нолей для десятичной записи числа x*2^y (y<0). И аналогично - количество завершающих нулей для x*2^y (y>0). Видимо нужно привести число к виду x*10^y.
     
  6. murder

    murder Member

    Публикаций:
    0
    Регистрация:
    3 июн 2007
    Сообщения:
    628
    Интересная закономерность: возьмём число 2^x

    И применим формулу:

    y=trunc((abs(x)-1-trunc((abs(x)-1)/10))/3)+1

    Если x>=0, то y - это длина десятичного числа
    Иначе это количество лидирующих нулей