2016-02-29 7 views
0

При ориентации C99, я мог бы усечь и разделить значение double на два 32-битовых целых чисел со следующим кодом:В C89, как я могу обрезать и разделить плавучую точку с двойной точностью на два 32-битных слова?

#include <stdint.h> 

void split(double d, unsigned long *most_significant_word, unsigned long *least_significant_word) 
{ 
    uint64_t i = (uint64_t)d; 
    *most_significant_word = i >> 32; 
    *least_significant_word = i & 0xffffffff; 
} 

C89 однако, не кажется, чтобы определить 64-битное целое типа, так что я могу Не используйте компилятор для выполнения усечения. Даже если усечение не было необходимым (значение уже представляло целое число), я также не мог использовать операторы битов, такие как & или >>, поскольку они не работают с значениями double.

Итак, как можно реализовать вышеприведенную функцию split() в чистом C89 (и, таким образом, не полагаясь на 64-битные целые числа), возвращая 21/32-битные слова, которые составляют 53-битовое целое, сохраненное в значении double?

+4

C89 не предоставляет 'stdint.h'. Вы оставляете конкретные детали реализации. Поскольку он не обеспечивает 'long long', как вы читаете 64-битное значение? – Olaf

+0

@ Olaf: однако C89 мандаты 'long' должны быть шириной не менее 32 бит. Использование 'unsigned long' должно быть прекрасным для выходов. –

+0

@MatteoItalia: И как это противоречит моему комментарию? Я думаю, что я четко написал, что это ** конкретная реализация **, а не невозможная. Просто полагаться на 'long', чтобы иметь 32 бита, является очень неправильным. См. POSIX64! Однако большая проблема - это 64-разрядный тип. – Olaf

ответ

3

Игнорирование знака (как это делает исходный код) он должен быть простым, как это:

void split(double d, unsigned long *most_significant_word, unsigned long *least_significant_word) 
{ 
    *most_significant_word = d/4294967296.; // d>>32 in double 
    *least_significant_word = fmod(d, 4294967296.); 
} 

Для того, чтобы отрицательные числа во внимание, действуют на абсолютное значение, то вычислить двоичное дополнение:

void split(double d, unsigned long *most_significant_word, unsigned long *least_significant_word) 
{ 
    double dabs = d < 0 ? -d : d; 
    *most_significant_word = dabs/4294967296.; 
    *least_significant_word = fmod(dabs, 4294967296.); 
    if (d < 0) { 
     *most_significant_word = ~*most_significant_word; 
     *least_significant_word = ~*least_significant_word + 1; 
     if (!*least_significant_word) *most_significant_word += 1; 
    } 
} 
+0

Это действительно просто, спасибо. Просто дайте мне несколько минут, чтобы проверить это. Было бы сложно изменить этот ответ, чтобы слова содержали дополнение двух в случае отрицательных чисел? –

+0

Лучше использовать 'exp2()' вместо 'pow()' для менее оптимизирующих компиляторов C. – fuz

+0

@MarkDickinson: непонятое целочисленное переполнение хорошо определено и делает то, что (я думаю) ожидает OP, т. Е. Принимает самые младшие 32 бита целого числа, хранящиеся в 'd', как это делает исходный код. Конечно, если он хочет извлечь необработанные биты двойника, это совсем другой вопрос (лучше всего выполняется с помощью «memcpy»), но это не тот код, который он предоставил. –

 Смежные вопросы

  • Нет связанных вопросов^_^