Shift-left «двойной» операнд

0

Следующая функция сдвигает-левый double операнд:

double shl(double x,unsigned long long n)
{
    unsigned long long* p = (unsigned long long*)&x;
    *p += n << 52;
    return x;
}

Является ли эта функция гарантией правильной работы на всех платформах?

Вы можете принять правильную комбинацию x и n (т.е. x*2^n не переполняется).


Другими словами, я спрашиваю, диктует ли языковой стандарт следующее:

  1. Экспоненциальные биты типа double - 52,53,54,55,56,57,58,59,60,61,62

  2. Бит-размер double равен битовому размеру unsigned long long 64

  3. Правило строгого сглаживания для double и unsigned long long не нарушается

Если ответы для C и для C++ различны, то я хотел бы знать каждый из них.

  • 0
    Я не думаю, что стандарт обещает какой-либо из 3 пунктов, которые вы перечислите.
  • 0
    Кроссворк C, например, может иметь 32b дублей
Показать ещё 4 комментария
Теги:
bit-shift
double

3 ответа

8
Лучший ответ

Нет, ни C, ни C++ не диктуют представление типов с плавающей точкой в стандарте языка, хотя рекомендуется использовать формат IEEE и предполагается, что макрос (__STDC_IEC_559__) будет доступен для определения того, используется ли он.

У вашего решения есть несколько проблем в дополнение к различным представлениям. Вы уже заметили строгое нарушение псевдонимов... оптимизатор может превратить вашу всю функцию в no-op, так как ни один double не изменяется между началом функции и возвращаемым значением, он может предположить, что x не изменяется. Вы могли бы дополнительно иметь проблему переполнения - вам понадобится какая-то форма насыщающей арифметики, которая не позволяет результату переносить знаковый бит.

Однако вам не нужно возиться с этим, поскольку стандартная библиотека уже содержит функцию, которую вы пытаетесь написать.

Он называется ldexpldexpf для float).

  • 0
    Ну, я сказал «предположим, что x*2^n не переполняется» ... Но кроме этого он отвечает на мой вопрос с полной (двойной) точностью. Спасибо.
2

Для C++:

  1. Нет. C++ не требует плавающей точки IEEE. Он даже не требует двоичных показателей.

  2. Точно нет. Unsigned long long может быть более 64 бит. Двойным может быть не 64 бит.

  3. Такой тип пиннинга небезопасен.

  • 0
    double не может быть меньше 64 бит из-за требований к значениям в float.h
  • 0
    @ BenVoigt: Если я правильно помню, double должен быть больше 32 бит, но я не думаю, что он должен быть 64 бит. Я не помню точных деталей.
Показать ещё 2 комментария
1

Этот код определенно не сдвигает двойной операнд влево. Он выполняет какие-то манипуляции с битами, возможно, в надежде, что показатель двойного числа будет изменен.

Как бы то ни было, код вызывает неопределенное поведение, поскольку lvalue записывается с использованием длинного длинного типа и затем считывается с использованием типа double. В результате все может произойти. Это самый неуправляемый код, который вы могли бы получить.

  • 0
    Спасибо, я имел ввиду эквивалент для сдвига влево.
  • 0
    Ваше перефразирование строгого псевдонима не совсем верно. В динамически распределенной памяти эффективный тип объекта - это то, что было в нем в последний раз сохранено; но для именованной переменной эффективным типом является объявленный тип; Например, вы не можете объявить unsigned long long а затем записать в нее число с плавающей точкой и снова прочитать его обратно (даже если выравнивание правильное). (Это для C; C ++ немного отличается)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню