Быстрое извлечение мантиссы и экспоненты (frexp())
От: cepstr Беларусь  
Дата: 03.05.08 10:53
Оценка:
Здравствуйте.

Есть кусок кода, который активно использует функцию frexp():

double frexp(
double x,
int *expptr
);

Gets the mantissa and exponent of a floating-point number.

Компилятор -- MS VC++ 9.0, релиз, оптимизация по скорости.
Профайлер показывает, что эта функция занимает 30% процессорного времени. Если смотреть в asm, то видно, что frexp() вызывается через call, причём внутри она вызывает ещё несколько вспомогательных функций. Intrinsic'a для frexp() в MSVC похоже нет, и заставить компилятор генерировать код без инструкций call я не смог.

Вопрос: как достать из double'а экспоненту и мантиссу максимально быстро?
Я не знаком глубоко с системой команд x86/87, но подозреваю, что FPU должен уметь это делать (знатоки, что скажете?). Очень хочется избваится от call'ов.

Лучшее что я пока придумал -- это доставать мантиссу/экспоненту зная побитное представление double'а при помощи битовых операций. Работает заметно быстрее чем frexp(), но выглядит не элегантно.

А как ещё?
Re: Быстрое извлечение мантиссы и экспоненты (frexp())
От: Sergey Chadov Россия  
Дата: 03.05.08 11:06
Оценка:
Здравствуйте, cepstr, Вы писали:


C>Вопрос: как достать из double'а экспоненту и мантиссу максимально быстро?

C>Я не знаком глубоко с системой команд x86/87, но подозреваю, что FPU должен уметь это делать (знатоки, что скажете?). Очень хочется избваится от call'ов.

Команда называется fxtract, но насчет быстрее/медленнее надо проыодить эксперименты.
--
Sergey Chadov

... << RSDN@Home 1.2.0 alpha rev. 685>>
Re: Быстрое извлечение мантиссы и экспоненты (frexp())
От: Programador  
Дата: 03.05.08 18:22
Оценка:
Здравствуйте, cepstr,

http://www.rsdn.ru/article/alg/float.xml
Автор(ы): Сергей Холодилов
Дата: 15.03.2008
Если яблоко поровну разделить на троих, каждому достанется треть. Так в нашу жизнь входят дроби, примерно с теми же целями входят они и в программирование.. Но реализация дробей в виде типов данных float/double ведёт себя не совсем "математично". В чём причина отличий, как минимизировать их влияние на результат вычислений, как же всё это всё-таки реализовано и почему запятая плавает — читайте в статье.
здесь описание формата
Re[2]: Быстрое извлечение мантиссы и экспоненты (frexp())
От: sokel Россия  
Дата: 05.05.08 13:41
Оценка:
Здравствуйте, Programador, Вы писали:

P>Здравствуйте, cepstr,


P>http://www.rsdn.ru/article/alg/float.xml
Автор(ы): Сергей Холодилов
Дата: 15.03.2008
Если яблоко поровну разделить на троих, каждому достанется треть. Так в нашу жизнь входят дроби, примерно с теми же целями входят они и в программирование.. Но реализация дробей в виде типов данных float/double ведёт себя не совсем "математично". В чём причина отличий, как минимизировать их влияние на результат вычислений, как же всё это всё-таки реализовано и почему запятая плавает — читайте в статье.
здесь описание формата


union parsed_double
{
    double v;                 // значение
    struct
    {
        unsigned int m0;      // младшие биты мантиссы
        unsigned int m1 : 20; // старшие биты мантиссы
        unsigned int e  : 11; // показатель степени
        unsigned int s  : 1;  // знак
    } d;
};
inline double __frexp(double value, int* exponent)
{
    parsed_double& pd = (parsed_double&)value;
    *exponent = pd.d.e - 1022;
    pd.d.e = 1022;
    return value;
}


test_count: 1000000, frexp(12345.12345)

frexp:1969 ms
__frexp:219 ms
Re[3]: Быстрое извлечение мантиссы и экспоненты (frexp())
От: sokel Россия  
Дата: 05.05.08 13:59
Оценка:
Здравствуйте, sokel, Вы писали:

S>Здравствуйте, Programador, Вы писали:


P>>Здравствуйте, cepstr,


P>>http://www.rsdn.ru/article/alg/float.xml
Автор(ы): Сергей Холодилов
Дата: 15.03.2008
Если яблоко поровну разделить на троих, каждому достанется треть. Так в нашу жизнь входят дроби, примерно с теми же целями входят они и в программирование.. Но реализация дробей в виде типов данных float/double ведёт себя не совсем "математично". В чём причина отличий, как минимизировать их влияние на результат вычислений, как же всё это всё-таки реализовано и почему запятая плавает — читайте в статье.
здесь описание формата


или даже так побыстрей будет, только надо проверки на граничные значения ещё прицепить:

inline double __frexp(double value, int* exponent)
{
    __int64& ivalue = (__int64&) value;
    *exponent = (int)((ivalue&0x7FF0000000000000L)>>52) - 1022;
    ivalue&=0x800FFFFFFFFFFFFFL;
    ivalue|=0x3FE0000000000000L;
    return value;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.