возникла задача. весьма интересная. есть алгоритм преобразования чисел с плавающей точкой из формата IBM 370 float в формат IEEE 754 x86 float пару оптимизаций сделал, но толком вроде как не развернуть. с одной стороны — можно обрабатывать кучей по несколько чисел, но мешают многочисленные условные переходы (while, if) вожможно ли оптимизировать? заранее благодарен за советы, идеи. Код (Text): void ibm2ieee(void *to, const void *from, int len) { register unsigned fr; /* fraction */ register int exp; /* exponent */ register int sgn; /* sign */ for (; len-- > 0; to = (char *)to + 4, from = (char *)from + 4) { /* split into sign, exponent, and fraction */ fr = ntohl(*(long *)from); /* оборот 4 байтов, можно применить ассемблерное [b]bswap[/b]*/ sgn = fr | 0x80000000; /* знак числа */ fr <<= 1; /* shift sign out */ exp = fr >> 25; /* save exponent */ fr <<= 7; /* shift exponent out */ if (fr == 0) { /* short-circuit for zero */ *(unsigned *)to = 0; continue; } /* adjust exponent from base 16 offset 64 radix point before first digit to base 2 offset 127 radix point after first digit */ /* (exp - 64) * 4 + 127 - 1 == exp * 4 - 256 + 126 == (exp << 2) - 130 */ exp = (exp << 2) - 130; /* (re)normalize, фактически можно заменить на ассемблерное [b]bsr[/b]*/ while (fr < 0x80000000) { /* 3 times max for normalized input */ --exp; fr <<= 1; } if (exp <= 0) { /* underflow */ if (exp < -24) /* complete underflow - return properly signed zero */ fr = 0; else /* partial underflow - return denormalized number */ fr >>= -exp; exp = 0; } else if (exp >= 255) { /* overflow - return infinity */ fr = 0; exp = 255; } else { /* just a plain old number - remove the assumed high bit */ fr <<= 1; } /* put the pieces back together and return it */ *(unsigned *)to = (fr >> 9) | (exp << 23) | sgn; } }
ИМХО сохранять денормальные значения смысла нет - и вероятность мала и лишние тормоза как при преобразовании, так и при последующей обработке полученных чисел на FPU. Лучше заменять денормальные значения на 0. На асме преобразование может выглядеть примерно так Код (Text): ; s e f ;IBM 1 7 24 (-1)^s*0.f * 16^(e-64) ;IEEE 1 8 23 (-1)^s*1.f * 2^(e-127) ;void _stdcall ibm2ieee(void *to, const void *from, int len) ;{_asm{ push edi push esi push ebx mov edi,from mov esi,to mov edx,len lea edi,[edi+edx*4] lea esi,[esi+edx*4] neg edx _loop: mov eax,[edi+edx*4] ;bswap eax ;??? а надо ли ? mov ebx,eax and eax,00FFFFFFh ;мантисса jz _store bsr ecx,eax ;ищем старший бит мантиссы and ebx,0FF000000h ;знак и порядок sub ecx,24 ;поправка к порядку мантиссы neg ecx shl eax,cl ;сдвигаем мантиссу or eax,ebx ;копируем знак shr ebx,1 ;сдвигаем порядок from, выбрасывая знак add ecx,64*4-127 ;вычисляем поправку к порядку shl ecx,23 ;сдвигаем на место and eax,807FFFFFh ;зануляем порядок to и старший бит мантиссы sub ebx,ecx ;корректируем порядок mov ecx,0 ;зануляем ecx на сл. underflow jbe _underflow cmp ebx,7F800000h jae _overflow or eax,ebx _store: mov [esi+edx*4],eax add edx,1 jnz _loop jmp _exit _overflow: mov ecx,7F800000h ;infinity _underflow: and eax,80000000h or eax,ecx mov [esi+edx*4],eax add edx,1 jnz _loop _exit: pop ebx pop esi pop edi ;}}
спасибо большое за мысли! вот что у меня получилось (искал параллельно): Код (Text): for( i=0; i<n; ++i) { fconv = from[i]; fconv = ntohl(*(long *)fconv); /* оборот 4 байтов, можно применить ассемблерное bswap. сие не всегда обязательно, но в большинстве случаев - нужно оборачивать 4 байта :( */ if (fmant = (0x00ffffff & fconv)){ exp = (int) ((0x7f000000 & fconv) >> 22) - 130; unsigned long position; asm ("bsrl %1, %0" : "=r" (position): "r" (fmant)); position = 23 - position; exp -= position; fmant <<= position; fconv = (0x80000000 & fconv); /* save sign */ if (exp>0 && exp<255){ fconv = fconv |(exp << 23)|(0x007fffff & fmant); } else{ fconv = (exp > 254)?(fconv | 0x7f7fffff):0; } from[i] = fconv; } } а вот интересно, можно ли сделать так, чтобы избавиться от внутрицикловых джампов, для того, чтобы оптимальнее использовать конвейеры и/или MMX/SSE... (может быть совсем ламерский вопрос... )?