Меня удивило, что следующий код возвращает false для gcc 13 и clang 18. Почему это происходит? Разве число 8.1 не представимо в обоих форматах?
#include <iostream>
#include <iomanip>
int main()
{
const long double val = 8.1L;
const double val2 = static_cast<double>(val);
const long double val3 = static_cast<long double>(val2);
std::cout << std::boolalpha << (val == val3) << '\n';
return 0;
}
Это зависит не только от компилятора, но и от базовой среды (ОС, оборудования) и используемой стандартной библиотеки. Есть системы, в которых sizeof(double) == sizeof(long double)
верно, и есть системы, в которых это ложь.
Вскоре после написания вопроса я понял, что он не совсем представим и поэтому может отличаться в обоих форматах.
№ 8.1 не представим. Например, 1/3 = 0,33333.... в десятичном виде (сколько бы цифр вы ни вводили, это все равно не 1/3). То же самое для «8.1» в двоичном формате 1000.0001 1001 1001 [1001].. (группа 1001 начинает повторяться бесконечно)
Разве число 8.1 не представимо в обоих форматах?
Нет, 8.1 не может быть представлен ни в каком формате с плавающей запятой, в котором в качестве основы используется два.
Если число может быть представлено в формате с плавающей запятой, оно может быть представлено в форме ±M•be, где b — это основание, используемое для формата, а M и e — целые числа. Существуют ограничения на M и e, которые зависят от формата, и часть M часто записывается как число с фиксированной точкой, а не целое число, но это всего лишь изменение масштаба. Представление целым числом математически эквивалентно.
С основанием два 8,125 можно представить как +65•2−3, потому что 8,125•23 = 65. Однако не существует степени двойки, на которую можно было бы умножить 8,1, чтобы получить целое число. 8,1•2 = 16,2. 16,2•2 = 32,4. 32,4•2 = 64,8. 64,8•2 = 129,6. 129,6•2 = 259,2. 259,2•2 = 518,4. Вы можете увидеть цифру после зацикливания десятичной точки: .2, .4, .8, .6, .2, .4, .8, .6, .2,… Она никогда не исчезнет.
8.1 в двоичном формате — это 1000.00011001100110011001100110011001100110011001100110011…2.
Формат, обычно используемый для double
, IEEE-754binary64, имеет 53 бита для своего мантисса. При преобразовании 8.1 в этот формат оно будет округлено до 53 бит. (Результат этого округления: 8,0999999999999996447286321199499070644378662109375.)
Я не знаю, какой формат используется в вашей реализации long double
, но, вероятно, он имеет значительно больше 53 бит, скажем, p бит. Когда 8.1 округляется до этого формата, оно округляется до p бит. Ваша переменная long double
val
получает это округленное значение.
Когда оценивается static_cast<double>(val)
, это значение округляется до 53 бит, и val2
получает это значение. Это значение, отличное от val
.
распечатайте
sizeof(double)
иsizeof(long double)
. Еслиlong double
больше, это означает, что оно может быть более точным, в нем больше битов. Это важно, потому что.1
не представимо в базе 2, вместо этого вы получаете близкое приближение.