Следующая функция сдвигает-левый 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
не переполняется).
Другими словами, я спрашиваю, диктует ли языковой стандарт следующее:
Экспоненциальные биты типа double
- 52,53,54,55,56,57,58,59,60,61,62
Бит-размер double
равен битовому размеру unsigned long long
64
Правило строгого сглаживания для double
и unsigned long long
не нарушается
Если ответы для C и для C++ различны, то я хотел бы знать каждый из них.
Нет, ни C, ни C++ не диктуют представление типов с плавающей точкой в стандарте языка, хотя рекомендуется использовать формат IEEE и предполагается, что макрос (__STDC_IEC_559__
) будет доступен для определения того, используется ли он.
У вашего решения есть несколько проблем в дополнение к различным представлениям. Вы уже заметили строгое нарушение псевдонимов... оптимизатор может превратить вашу всю функцию в no-op, так как ни один double
не изменяется между началом функции и возвращаемым значением, он может предположить, что x
не изменяется. Вы могли бы дополнительно иметь проблему переполнения - вам понадобится какая-то форма насыщающей арифметики, которая не позволяет результату переносить знаковый бит.
Однако вам не нужно возиться с этим, поскольку стандартная библиотека уже содержит функцию, которую вы пытаетесь написать.
Он называется ldexp
(и ldexpf
для float
).
x*2^n
не переполняется» ... Но кроме этого он отвечает на мой вопрос с полной (двойной) точностью. Спасибо.
Для C++:
Нет. C++ не требует плавающей точки IEEE. Он даже не требует двоичных показателей.
Точно нет. Unsigned long long может быть более 64 бит. Двойным может быть не 64 бит.
Такой тип пиннинга небезопасен.
double
не может быть меньше 64 бит из-за требований к значениям в float.h
double
должен быть больше 32 бит, но я не думаю, что он должен быть 64 бит. Я не помню точных деталей.
Этот код определенно не сдвигает двойной операнд влево. Он выполняет какие-то манипуляции с битами, возможно, в надежде, что показатель двойного числа будет изменен.
Как бы то ни было, код вызывает неопределенное поведение, поскольку lvalue записывается с использованием длинного длинного типа и затем считывается с использованием типа double. В результате все может произойти. Это самый неуправляемый код, который вы могли бы получить.
unsigned long long
а затем записать в нее число с плавающей точкой и снова прочитать его обратно (даже если выравнивание правильное). (Это для C; C ++ немного отличается)