Какое самое большое целое число, которое не может быть плавающим, может быть сохранено в двойном типе IEEE 754 без потери точности?
наибольшее целое число, которое может быть сохранено в двойном
Ответы (8)
Наибольшее / наибольшее целое число, которое может быть сохранено в double без потери точности, совпадает с наибольшим возможным значением double. То есть DBL_MAX
или примерно 1,8 × 10 308 (если ваш дубль является 64-битным двойником IEEE 754). Это целое число. Он представлен точно. Что вы еще хотите?
Продолжайте, спросите меня, какое наибольшее целое число, чтобы его и все меньшие целые числа можно было сохранить в 64-битных числах IEEE с двойной точностью без потери точности. 64-битный двойной IEEE имеет 52 бита мантиссы, поэтому я думаю, что это 2 53:
- 2 53 + 1 не может быть сохранен, потому что 1 в начале и 1 в конце имеют слишком много нулей между ними.
- Все, что меньше 2 53, может быть сохранено с 52 битами, явно сохраненными в мантиссе, а затем действительный показатель степени дает вам еще один.
- 2 53, очевидно, можно сохранить, так как это малая степень двойки.
Или другой способ взглянуть на это: после того, как смещение было снято с экспоненты и игнорируя знаковый бит как не имеющий отношения к вопросу, значение, сохраненное двойным, является степенью 2 плюс 52-битное целое число, умноженное на 2 показатель степени - 52. Таким образом, с показателем 52 вы можете сохранить все значения от 2 52 до 2 53 - 1. Затем с показателем 53 следующее число, которое вы можете сохранить после 2 53 равно 2 53 + 1 × 2 53–52. Итак, потеря точности сначала происходит с 2 53 + 1.
double
является точным, и это наибольшее целое число с этим свойством. Следовательно, он отвечает на заголовок этого вопроса, наибольшее целое число, которое может быть сохранено в двойном формате. Я не думаю, что смогу объяснить что-то еще, ведь объяснение шутки ограничено.
- person Steve Jessop; 23.09.2013
-(2^53)
?
- person Levi Morrison; 30.11.2017
9.0071993e+15
, но мне нужно точное значение.
- person Aaron Franke; 16.01.2020
0x4340000000000000
. Такой конвертер, как weitz.de/ieee, может помочь вам понять, почему (доступны другие, это только первый Я нашел).
- person Steve Jessop; 26.05.2020
long long
(64-битное целое число со знаком) в double
. Я хочу показать сообщение об ошибке, если число в long long
слишком велико или слишком мало для представления double
. Какие границы я должен проверить? В своем ответе вы указываете 2 ^ 53 как верхний предел, но как насчет отрицательных чисел? Какое наименьшее целое число я могу сохранить в double
?
- person Andreas; 15.07.2020
-2^53
- это просто 2^53
с перевернутым знаковым битом. -2^53 - 1
не может быть представлен по той же причине, что и 2^53 + 1
.
- person Steve Jessop; 15.07.2020
double
, равно 0. -1 squllion меньше 0, но он не меньше, это большое отрицательное число ;-)
- person Steve Jessop; 15.07.2020
(double)-9007199254740992LL == ((double)-9007199254740992LL) - 1
истинно. (double)-9007199254740992LL == ((double)-9007199254740992LL) + 1
ложно. Итак, -2^53
- это точка, в которой double
теряет точность.
- person Steve Jessop; 15.07.2020
long long x = 9007199254740992; double y = (double) x; printf("%.14g\n", y);
он печатает 9.007199254741e+015
, что на 9007199254741000
так на 8 больше, чем мое первоначальное long long
. Это почему?
- person Andreas; 15.07.2020
%.14g
. У вас всего 13, но это потому, что для 14 мест это 9.007199254741 0 e + 015, а завершающий 0 не печатается. Попробуйте %.16g
.
- person Steve Jessop; 15.07.2020
9007199254740992 (это 9 007 199 254 740 992 или 2 ^ 53) без каких-либо гарантий :)
Программа
#include <math.h>
#include <stdio.h>
int main(void) {
double dbl = 0; /* I started with 9007199254000000, a little less than 2^53 */
while (dbl + 1 != dbl) dbl++;
printf("%.0f\n", dbl - 1);
printf("%.0f\n", dbl);
printf("%.0f\n", dbl + 1);
return 0;
}
Результат
9007199254740991 9007199254740992 9007199254740992
double dbl = 1; while (dbl + 1 != dbl) dbl *= 2; while (dbl == --dbl);
, который дает тот же результат.
- person Seph; 06.03.2012
while (dbl == --dbl)
будет зацикливаться вечно или не будет вообще. :) (в данном случае совсем нет, так как это 2 ^ N). Подойти к нему придется снизу. Это действительно также приведет к результату на единицу меньше ожидаемого (поскольку одна проверка в цикле while уменьшает dbl). И это зависит от порядка выполнения, если декремент выполняется до или после оценки левой части (которая, насколько мне известно, не определена). Если это первое, это всегда будет правдой и будет повторяться вечно.
- person falstro; 25.10.2016
while (dbl + 1 != dbl) dbl++;
в том, что dbl + 1 != dbl
может оцениваться с помощью long double
математики - подумайте о FLT_EVAL_METHOD == 2
. Это могло закончиться бесконечным циклом.
- person chux - Reinstate Monica; 25.09.2018
dbl + 1 != dbl
бесконечно верно. Это связано с тем, что в 64-битном gcc
по умолчанию используется sse
, в 32-битном случае это не так. Пример ведет себя аналогично в 32-битном режиме при передаче -mfpmath=sse
в gcc
.
- person Daniel Da Cunha; 10.09.2019
0x20000000000000
.
- person Aaron Franke; 16.01.2020
В Википедии это говорится в том же контексте со ссылкой на IEEE 754:
В типичной компьютерной системе двоичное число с плавающей запятой «двойной точности» (64-битное) имеет коэффициент 53 бита (один из которых подразумевается), показатель степени 11 бит и один бит знака.
2 ^ 53 чуть больше 9 * 10 ^ 15.
Наибольшее целое число, которое может быть представлено в IEEE 754 double (64-битное), совпадает с наибольшим значением, которое может представлять тип, поскольку это значение само является целым числом.
Он представлен как 0x7FEFFFFFFFFFFFFF
, который состоит из:
- Знаковый бит 0 (положительный), а не 1 (отрицательный)
- Максимальный показатель степени
0x7FE
(2046, который представляет 1023 после вычитания смещения), а не0x7FF
(2047, который указываетNaN
или бесконечность). - Максимальная мантисса
0xFFFFFFFFFFFFF
, которая составляет 52 бита, все 1.
В двоичном формате значение - это неявная 1, за которой следуют еще 52 единицы из мантиссы, затем 971 ноль (1023 - 52 = 971) из экспоненты.
Точное десятичное значение:
179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368
Это примерно 1,8 x 10 308.
Нужно смотреть на размер мантиссы. 64-битное число с плавающей запятой IEEE 754 (которое имеет 52 бита, плюс подразумевается 1) может точно представлять целые числа с абсолютным значением, меньшим или равным 2 ^ 53.
1.7976931348623157 × 10^308
http://en.wikipedia.org/wiki/Double_precision_floating-point_format
Это правда, что для 64-битного IEEE754 double все целые числа до 9007199254740992 == 2 ^ 53 могут быть точно представлены.
Однако стоит также отметить, что все представимые числа за пределами 4503599627370496 == 2 ^ 52 являются целыми числами. За пределами 2 ^ 52 становится бессмысленным проверять, являются ли они целыми числами, потому что все они неявно округляются до ближайшего представимого значения.
В диапазоне от 2 ^ 51 до 2 ^ 52 единственными нецелыми значениями являются средние точки, оканчивающиеся на 0,5, что означает, что любой целочисленный тест после вычисления должен дать как минимум 50% ложных ответов.
Ниже 2 ^ 51 у нас также есть 0,25 и 0,75, поэтому сравнение числа с его округленным эквивалентом, чтобы определить, может ли оно быть целым или нет, начинает иметь некоторый смысл.
TL; DR: если вы хотите проверить, может ли вычисленный результат быть целым числом, избегайте чисел больше 2251799813685248 == 2 ^ 51
Как отмечали другие, я предполагаю, что OP запросил наибольшее значение с плавающей запятой, чтобы все целые числа, меньшие, чем он сам, были точно представлены.
Вы можете использовать FLT_MANT_DIG
и DBL_MANT_DIG
, определенные в float.h
, чтобы не полагаться на явные значения (например, 53):
#include <stdio.h>
#include <float.h>
int main(void)
{
printf("%d, %.1f\n", FLT_MANT_DIG, (float)(1L << FLT_MANT_DIG));
printf("%d, %.1lf\n", DBL_MANT_DIG, (double)(1L << DBL_MANT_DIG));
}
выходы:
24, 16777216.0
53, 9007199254740992.0