преобразование flot из ibm в ieee 754

Тема в разделе "WASM.A&O", создана пользователем Karbofos, 14 янв 2006.

  1. Karbofos

    Karbofos New Member

    Публикаций:
    0
    Регистрация:
    11 янв 2006
    Сообщения:
    4
    возникла задача. весьма интересная.

    есть алгоритм преобразования чисел с плавающей точкой из формата IBM 370 float в формат IEEE 754 x86 float

    пару оптимизаций сделал, но толком вроде как не развернуть. с одной стороны — можно обрабатывать кучей по несколько чисел, но мешают многочисленные условные переходы (while, if)

    вожможно ли оптимизировать?



    заранее благодарен за советы, идеи.


    Код (Text):
    1.  
    2. void ibm2ieee(void *to, const void *from, int len)
    3. {
    4.    register unsigned fr;   /* fraction */
    5.    register int exp;       /* exponent */
    6.    register int sgn;       /* sign */
    7.  
    8.    for (; len-- > 0; to = (char *)to + 4, from = (char *)from + 4) {
    9.       /* split into sign, exponent, and fraction */
    10.       fr = ntohl(*(long *)from); /* оборот 4 байтов, можно применить ассемблерное [b]bswap[/b]*/
    11.       sgn = fr | 0x80000000;     /* знак числа */
    12.       fr <<= 1;               /* shift sign out */
    13.       exp = fr >> 25;         /* save exponent */
    14.       fr <<= 7;               /* shift exponent out */
    15.  
    16.       if (fr == 0) { /* short-circuit for zero */
    17.          *(unsigned *)to = 0;
    18.          continue;
    19.       }
    20.  
    21.       /* adjust exponent from base 16 offset 64 radix point before first digit
    22.          to base 2 offset 127 radix point after first digit */
    23.       /* (exp - 64) * 4 + 127 - 1 == exp * 4 - 256 + 126 == (exp << 2) - 130 */
    24.            
    25.       exp = (exp << 2) - 130;
    26.  
    27.       /* (re)normalize, фактически можно заменить на ассемблерное [b]bsr[/b]*/
    28.       while (fr < 0x80000000) {  /* 3 times max for normalized input */
    29.          --exp;
    30.          fr <<= 1;
    31.       }
    32.  
    33.       if (exp <= 0) {   /* underflow */
    34.          if (exp < -24) /* complete underflow - return properly signed zero */
    35.             fr = 0;
    36.          else           /* partial underflow - return denormalized number */
    37.             fr >>= -exp;
    38.          exp = 0;
    39.       } else if (exp >= 255) {   /* overflow - return infinity */
    40.          fr = 0;
    41.          exp = 255;
    42.       } else { /* just a plain old number - remove the assumed high bit */
    43.          fr <<= 1;
    44.       }
    45.  
    46.       /* put the pieces back together and return it */
    47.       *(unsigned *)to = (fr >> 9) | (exp << 23) | sgn;
    48.    }
    49. }
    50.  
     
  2. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    ИМХО сохранять денормальные значения смысла нет - и вероятность мала и лишние тормоза как при преобразовании, так и при последующей обработке полученных чисел на FPU. Лучше заменять денормальные значения на 0. На асме преобразование может выглядеть примерно так
    Код (Text):
    1. ;        s    e     f
    2. ;IBM     1    7    24   (-1)^s*0.f * 16^(e-64)
    3. ;IEEE    1    8    23   (-1)^s*1.f * 2^(e-127)
    4. ;void _stdcall ibm2ieee(void *to, const void *from, int len)
    5. ;{_asm{
    6.   push edi
    7.   push esi
    8.   push ebx
    9.   mov edi,from
    10.   mov esi,to
    11.   mov edx,len
    12.   lea edi,[edi+edx*4]
    13.   lea esi,[esi+edx*4]
    14.   neg edx
    15.  
    16. _loop:
    17.   mov eax,[edi+edx*4]
    18.   ;bswap eax           ;??? а надо ли ?
    19.   mov ebx,eax
    20.   and eax,00FFFFFFh    ;мантисса
    21.   jz  _store
    22.   bsr ecx,eax          ;ищем старший бит мантиссы
    23.   and ebx,0FF000000h   ;знак и порядок
    24.   sub ecx,24           ;поправка к порядку мантиссы
    25.   neg ecx
    26.   shl eax,cl           ;сдвигаем мантиссу
    27.   or  eax,ebx          ;копируем знак
    28.   shr ebx,1            ;сдвигаем порядок from, выбрасывая знак
    29.   add ecx,64*4-127     ;вычисляем поправку к порядку
    30.   shl ecx,23           ;сдвигаем на место
    31.   and eax,807FFFFFh    ;зануляем порядок to и старший бит мантиссы
    32.   sub ebx,ecx          ;корректируем порядок
    33.   mov ecx,0            ;зануляем ecx на сл. underflow
    34.   jbe _underflow
    35.   cmp ebx,7F800000h
    36.   jae _overflow
    37.   or eax,ebx
    38. _store:
    39.   mov [esi+edx*4],eax
    40.   add edx,1
    41.   jnz _loop
    42.   jmp _exit
    43.  
    44. _overflow:
    45.   mov ecx,7F800000h   ;infinity
    46. _underflow:
    47.   and eax,80000000h
    48.   or eax,ecx
    49.   mov [esi+edx*4],eax
    50.   add edx,1
    51.   jnz _loop
    52.  
    53. _exit:
    54.   pop ebx
    55.   pop esi
    56.   pop edi
    57. ;}}
     
  3. Karbofos

    Karbofos New Member

    Публикаций:
    0
    Регистрация:
    11 янв 2006
    Сообщения:
    4
    спасибо большое за мысли! :)

    вот что у меня получилось (искал параллельно):


    Код (Text):
    1.  
    2.   for( i=0; i<n; ++i) {
    3.     fconv = from[i];
    4.     fconv = ntohl(*(long *)fconv); /* оборот 4 байтов, можно применить ассемблерное bswap. сие не всегда обязательно, но в большинстве случаев - нужно оборачивать 4 байта :( */
    5.     if (fmant = (0x00ffffff & fconv)){
    6.       exp = (int) ((0x7f000000 & fconv) >> 22) - 130;
    7.       unsigned long position;
    8.       asm ("bsrl %1, %0" : "=r" (position): "r" (fmant));
    9.       position = 23 - position;
    10.       exp -= position;
    11.       fmant <<= position;
    12.  
    13.       fconv = (0x80000000 & fconv); /* save sign */
    14.  
    15.       if (exp>0 && exp<255){
    16.         fconv = fconv |(exp << 23)|(0x007fffff & fmant);
    17.       }
    18.       else{
    19.         fconv = (exp > 254)?(fconv | 0x7f7fffff):0;
    20.       }
    21.       from[i] = fconv;
    22.     }
    23.   }
    24.  




    а вот интересно, можно ли сделать так, чтобы избавиться от внутрицикловых джампов, для того, чтобы оптимальнее использовать конвейеры и/или MMX/SSE... (может быть совсем ламерский вопрос... :) )?