наибольшее целое число, которое может быть сохранено в двойном

Какое самое большое целое число, которое не может быть плавающим, может быть сохранено в двойном типе IEEE 754 без потери точности?


person Franck Freiburger    schedule 04.12.2009    source источник


Ответы (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.

person Steve Jessop    schedule 04.12.2009
comment
+1 Хорошая работа, заметив, что вопрос на самом деле не означает то, что, вероятно, имел в виду спрашивающий, и предоставил оба ответа (технически правильные и, вероятно, ожидаемые). - person Pascal Cuoq; 04.12.2009
comment
Или возиться и пытаться помочь, как я их обычно называю :-) - person Steve Jessop; 04.12.2009
comment
Я просто добавил больше точности в описание моего вопроса. Я говорил о самом большом целом числе, не плавающем с плавающей запятой. - person Franck Freiburger; 04.12.2009
comment
Я склоняюсь перед вашим превосходным анализом вопроса. +1, симпатичный! - person Carl Smotricz; 04.12.2009
comment
@Soubok, вы должны сначала определить, что такое неплавающее, потому что это точно не термин со стандартным значением! - person Pavel Minaev; 04.12.2009
comment
@ Карл: Все кланяются Стиву. Кто, черт возьми, такой Джон Скит? Джессоп :) - person Dan Moulding; 04.12.2009
comment
Я кланяюсь Тони Пони и никому другому. - person Steve Jessop; 04.12.2009
comment
@Pavel Minaev: Да, я знаю, но если я задам такой вопрос, к сожалению, это потому, что я не знаю всех стандартов :) - person Franck Freiburger; 04.12.2009
comment
Вы имеете в виду не все меньшие целые числа, вы имеете в виду все целые числа равной или меньшей величины. Потому что ниже 2 ^ 53 много отрицательных целых чисел, и они не могут быть представлены точно в двойном формате. - person Southern Hospitality; 05.12.2009
comment
Я имею в виду меньше, и это именно то, что я имею в виду, когда говорю меньше :-) -1000000 меньше единицы, но не меньше. - person Steve Jessop; 05.12.2009
comment
@SteveJessop, ты можешь объяснить первое предложение? почему наибольшее целое число, которое может быть сохранено в двойном без потери точности, совпадает с максимально возможным значением двойного? - person Pacerier; 21.09.2013
comment
@Pacerier: это целое число, и его представление как double является точным, и это наибольшее целое число с этим свойством. Следовательно, он отвечает на заголовок этого вопроса, наибольшее целое число, которое может быть сохранено в двойном формате. Я не думаю, что смогу объяснить что-то еще, ведь объяснение шутки ограничено. - person Steve Jessop; 23.09.2013
comment
@SteveJessop Все, что меньше 2 ^ 53, может быть сохранено, при этом 52 бита явно хранятся в мантиссе, а затем показатель степени дает вам еще один Я не мог правильно это понять; Вы говорите о неявном / скрытом бите, потому что я не могу представить, как экспонента дает 53-й бит. Просьба уточнить. - person legends2k; 19.06.2014
comment
@ legends2k: экспонента указывает положение неявного / скрытого бита. То есть действующий показатель степени дает дополнительную точность. - person Steve Jessop; 19.06.2014
comment
@SteveJessop Но разве неявный бит всегда в начале? Например, 1.XXX является значимым для минифлотов, которые имеют 1 знак, 4 бита показателя степени и 3 разряда значащего. - person legends2k; 19.06.2014
comment
@ legends2k: неявный бит фактически не существует в объектном представлении поплавка, поэтому он называется неявным. Так что да, это в начале значения. Что в представлении объекта говорит вам, где находится начало значения? Показатель степени. - person Steve Jessop; 19.06.2014
comment
Дополнительный бонус за умение. - person Mad Physicist; 31.07.2015
comment
Вы можете кодировать все, что меньше 2 ^ 53, потому что значение экспоненты может превышать 2 ^ 53, перемещая точку полностью вправо от мантиссы. Сказать, что показатель степени дает дополнительный бит, сбивает с толку. Если бы у нас было всего 5 бит экспоненты, например, вы не смогли бы кодировать целые числа от 2 ^ 33 до 2 ^ 53 даже с неявными 52 битами мантиссы + 1. - person Joan Charmant; 20.08.2016
comment
Какое связанное число на отрицательной стороне? -(2^53)? - person Levi Morrison; 30.11.2017
comment
@LeviMorrison: да, теми же аргументами, но с установленным битом знака. - person Steve Jessop; 10.01.2018
comment
Каково точное значение 2 ^ 53? Калькулятор Google просто говорит 9.0071993e+15, но мне нужно точное значение. - person Aaron Franke; 16.01.2020
comment
@Aaron: гм, точное значение - 9007199254740992. В качестве 64-битного числа с плавающей запятой это число со знаком 0, значащие биты все нулевые, а показатель степени +53. Битовая комбинация - 0x4340000000000000. Такой конвертер, как weitz.de/ieee, может помочь вам понять, почему (доступны другие, это только первый Я нашел). - person Steve Jessop; 26.05.2020
comment
@SteveJessop: Я хочу преобразовать long long (64-битное целое число со знаком) в double. Я хочу показать сообщение об ошибке, если число в long long слишком велико или слишком мало для представления double. Какие границы я должен проверить? В своем ответе вы указываете 2 ^ 53 как верхний предел, но как насчет отрицательных чисел? Какое наименьшее целое число я могу сохранить в double? - person Andreas; 15.07.2020
comment
@Andreas: Поплавки IEEE имеют отдельный знаковый бит, поэтому они полностью симметричны относительно 0. -2^53 - это просто 2^53 с перевернутым знаковым битом. -2^53 - 1 не может быть представлен по той же причине, что и 2^53 + 1. - person Steve Jessop; 15.07.2020
comment
Сказав это, следуя умной теме моего ответа на исходный вопрос: наименьшее целое число, которое может представлять double, равно 0. -1 squllion меньше 0, но он не меньше, это большое отрицательное число ;-) - person Steve Jessop; 15.07.2020
comment
В любом случае вы можете убедить себя, фактически выполнив вычисление: (double)-9007199254740992LL == ((double)-9007199254740992LL) - 1 истинно. (double)-9007199254740992LL == ((double)-9007199254740992LL) + 1 ложно. Итак, -2^53 - это точка, в которой double теряет точность. - person Steve Jessop; 15.07.2020
comment
@SteveJessop: Но когда я делаю это: long long x = 9007199254740992; double y = (double) x; printf("%.14g\n", y); он печатает 9.007199254741e+015, что на 9007199254741000 так на 8 больше, чем мое первоначальное long long. Это почему? - person Andreas; 15.07.2020
comment
@Andreas: вы просили 14 цифр в формате code %.14g. У вас всего 13, но это потому, что для 14 мест это 9.007199254741 0 e + 015, а завершающий 0 не печатается. Попробуйте %.16g. - person Steve Jessop; 15.07.2020
comment
Интересно, что никто не упомянул связь этого вопроса с Javascript. Javascript не имеет целочисленного типа, все является плавающим (двойным), поэтому этот ответ дает вам диапазон целых чисел в Javascript. - person Mark Ransom; 28.03.2021

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
person pmg    schedule 04.12.2009
comment
Предполагая, что он будет «близким», но меньше 2 ^ N, тогда более быстрый тест - double dbl = 1; while (dbl + 1 != dbl) dbl *= 2; while (dbl == --dbl);, который дает тот же результат. - person Seph; 06.03.2012
comment
@Seph, что за ...? Нет? while (dbl == --dbl) будет зацикливаться вечно или не будет вообще. :) (в данном случае совсем нет, так как это 2 ^ N). Подойти к нему придется снизу. Это действительно также приведет к результату на единицу меньше ожидаемого (поскольку одна проверка в цикле while уменьшает dbl). И это зависит от порядка выполнения, если декремент выполняется до или после оценки левой части (которая, насколько мне известно, не определена). Если это первое, это всегда будет правдой и будет повторяться вечно. - person falstro; 25.10.2016
comment
Может быть, где-то указать, что 2 ^ 53 = 9,007,199,254,740,992. - person Xonatron; 24.10.2017
comment
С этим сложно поспорить! Хороший эксперимент - person MattM; 13.06.2018
comment
Слабость использования while (dbl + 1 != dbl) dbl++; в том, что dbl + 1 != dbl может оцениваться с помощью long double математики - подумайте о FLT_EVAL_METHOD == 2. Это могло закончиться бесконечным циклом. - person chux - Reinstate Monica; 25.09.2018
comment
FWIW, значение, которое вы указываете минус один (в терминах представления двойной точности IEEE 754), имеет показатель степени 1075-1023 = 52 и мантиссу со всеми (52) одним битом после десятичной точки. Следующее значение (900 ... 2) тогда имеет все (52) нули после десятичной точки в мантиссе и показатель степени 1076-1023 = 53. - person Andre Holzner; 12.03.2019
comment
При компиляции этого примера на 32-битной основе условие dbl + 1 != dbl бесконечно верно. Это связано с тем, что в 64-битном gcc по умолчанию используется sse, в 32-битном случае это не так. Пример ведет себя аналогично в 32-битном режиме при передаче -mfpmath=sse в gcc. - person Daniel Da Cunha; 10.09.2019
comment
В шестнадцатеричном формате это значение 0x20000000000000. - person Aaron Franke; 16.01.2020

В Википедии это говорится в том же контексте со ссылкой на IEEE 754:

В типичной компьютерной системе двоичное число с плавающей запятой «двойной точности» (64-битное) имеет коэффициент 53 бита (один из которых подразумевается), показатель степени 11 бит и один бит знака.

2 ^ 53 чуть больше 9 * 10 ^ 15.

person Carl Smotricz    schedule 04.12.2009
comment
@ Стив Джессоп, более или менее, я говорю именно об этом. Я также сталкивался с аппаратными системами, у которых нет FPU, которые все еще должны быть IEEE-совместимыми, так что типичные системные вещи действительно не помогут мне, если я вернусь сюда через 8 месяцев и мне понадобится та же информация для моего 68K. на базе микроконтроллера (при условии, что у него нет FPU ... не помню). - person San Jacinto; 04.12.2009
comment
@San Jacinto - Это бесполезно, слишком жестко. Ответ весьма полезен, но не так полезен, как если бы он содержал комментарий о том, что типичные компьютерные системы действительно используют представление IEEE 754. - person Stephen C. Steel; 04.12.2009
comment
@ Стивен К. Сталь, на самом деле вы правы. По моему сценарию, возвращаясь к этому позже и ища IEEE max, невозможно определить, что такое «типичная система», но, помимо этой жалобы, в ответе все еще есть достоинства. - person San Jacinto; 04.12.2009

Наибольшее целое число, которое может быть представлено в 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.

person Simon Biber    schedule 30.09.2016
comment
Как насчет наибольшего значения, которое он может представить, когда все значения между ним и нулем могут быть представлены непрерывно? - person Aaron Franke; 16.01.2020
comment
@AaronFranke Вопрос не касался непрерывного представления, но ответ на этот другой вопрос был включен в большинство других ответов здесь или даже неправильно указан как фактический ответ. Это 2⁵³ (2 в степени 53). - person Simon Biber; 29.04.2020

Нужно смотреть на размер мантиссы. 64-битное число с плавающей запятой IEEE 754 (которое имеет 52 бита, плюс подразумевается 1) может точно представлять целые числа с абсолютным значением, меньшим или равным 2 ^ 53.

person Dolphin    schedule 04.12.2009
comment
Он тоже может точно представлять 2 ^ 53 :-) - person Steve Jessop; 04.12.2009

1.7976931348623157 × 10^308

http://en.wikipedia.org/wiki/Double_precision_floating-point_format

person Jay    schedule 04.12.2009
comment
этот ответ был бы намного лучше с цитатой. - person San Jacinto; 04.12.2009
comment
@Carl ну, если целое число имеет нули слева, то оно точно сохраняется. - person Wilhelm; 04.12.2009
comment
@ все, кто проголосовал против: 1,7976931348623157 × 10 ^ 308 - точное целое число. Вам всем нужно посещать лечебные занятия по математике или что-то в этом роде ?? - person Dan Moulding; 04.12.2009
comment
Здесь мы переходим к семантике при обсуждении этого безнадежно провалившегося ответа. Правда, это число может быть представлено точно и тем самым соответствует букве вопроса. Но все мы знаем, что это крошечный островок точности в океане возможных промахов, и большинство из нас правильно интерполировали вопрос, обозначив наибольшее число, за которым точность падает насмарку. Ах, разве не чудесно, что CompSci - это точная наука? :) - person Carl Smotricz; 04.12.2009
comment
Это правильный ответ на вопрос. Значение DBL_MAX, которое является наибольшим значением, которое может представлять двойной IEEE, ЯВЛЯЕТСЯ точным целым числом: в двоичном представлении это 53 единицы, за которыми следует 971 ноль (и, конечно, его точное выражение в десятичной системе счисления составляет 308 цифр). Однако следующее меньшее точное целое число в представлении IEEE - 52 единицы, за которыми следуют 972 нуля (то есть пробел 2 ^ 971). То, что, вероятно, хотел OP, было верхним пределом целочисленных значений, которые могут быть представлены без пробелов, что составляет 2 ^ 53 (как указано в других ответах). - person Stephen C. Steel; 04.12.2009
comment
@Carl: Но, учитывая заданный вопрос, является ли этот ответ неправильным? Нет, конечно, не так. И никто на самом деле не знает, что OP имел в виду, кроме OP. Так зачем же отрицать правильный ответ? Потому что вы чувствуете, что способности Джейми читать мысли не на должном уровне? - person Dan Moulding; 04.12.2009
comment
Число, указанное выше, является точным значением DBL_MAX? Я не уверен, что это не так, но статья в Википедии, на которую указывает ссылка, указывает, что это приблизительное значение, и, безусловно, было бы некоторым совпадением, если число, определяемое пределами представления с основанием 2, делится на довольно много степени 10. Не то чтобы я отрицал это, просто в своем ответе я указал, что мое приближение действительно было приближением. - person Steve Jessop; 04.12.2009
comment
@ StephenC.Steel Я знаю, что опаздываю на вечеринку на 5 лет, но Double.MAX_VALUE составляет 1,797 ... x 10 ^ 308 = (((1 ‹---------------- 54) -1) * (1 ‹› 970)), что это 53 единицы, за которыми следуют всего 969 нулей. Наибольшее значение, которое может получить показатель степени, все еще представляя число, составляет 1022 минус 52 явных, а один неявный 1 оставляет нам 969. - person masterxilo; 02.06.2014
comment
@DanMoulding 1.7976931348623157 × 10 ^ 308 - точное целое число, но я почти уверен, что это конкретное целое число не может быть сохранено точно в двойном. - person Pascal Cuoq; 27.09.2014
comment
Примечание (на всякий случай, если кто-то ссылается на этот конкретный ответ): фактическое число указано в ответе Саймона Бибера. - person Alexey Romanov; 06.07.2018

Это правда, что для 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

person Jan Heldal    schedule 05.02.2021

Как отмечали другие, я предполагаю, что 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
person Jay Lee    schedule 09.05.2021