可以存储在 double 中的最大整数

Posted

技术标签:

【中文标题】可以存储在 double 中的最大整数【英文标题】:biggest integer that can be stored in a double 【发布时间】:2010-12-23 08:26:18 【问题描述】:

可以存储在 IEEE 754 双精度类型中而不会丢失精度的最大“非浮点”整数是多少?

【问题讨论】:

【参考方案1】:

在不丢失精度的情况下可以存储在双精度中的最大/最大整数与双精度的最大可能值相同。也就是说,DBL_MAX 或大约 1.8 × 10308(如果您的双精度是 IEEE 754 64 位双精度)。它是一个整数。它被准确地表示出来。你还想要什么?

继续,问我最大的整数是多少,这样它和所有较小的整数都可以存储在 IEEE 64 位双精度中而不会丢失精度。 IEEE 64 位双精度有 52 位尾数,所以我认为是 253

253 + 1 无法存储,因为开头的 1 和结尾的 1 之间的零太多。 可以存储任何小于 253 的值,其中 52 位显式存储在尾数中,然后有效的指数为您提供另一个。 253 显然可以存储,因为它是 2 的小幂。

或者另一种看待它的方式:一旦从指数中去除偏差,并忽略与问题无关的符号位,double 存储的值是 2 的幂,加上一个 52 位整数乘以 2指数 − 52。因此,使用指数 52,您可以存储从 252 到 253 − 1 的所有值。然后使用指数 53,您可以存储 253 之后的下一个数字 是 253 + 1 × 253 − 52。所以精度损失首先发生在 253 + 1.

【讨论】:

+1 很好地注意到这个问题并不真正意味着提问者可能的意图并提供两个答案(“技术上正确”和“可能预期”)。 或“搞砸”和“试图帮助”,因为我倾向于这样称呼他们:-) 我向小马托尼鞠躬,没有其他人。 您的意思不是“所有较小的整数”,而是所有大小相等或更小的整数。因为2^53以下有很多负整数,不能用double精确表示。 我的意思是更小,这正是我说更小的意思:-) -1,000,000 小于 1,但它并不更小。【参考方案2】:

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

【讨论】:

假设它将是“接近”但小于 2^N,那么更快的测试是double dbl = 1; while (dbl + 1 != dbl) dbl *= 2; while (dbl == --dbl);,它会产生相同的结果 @Seph 什么...?不? while (dbl == --dbl) 将永远循环或根本不循环。 :) (在这种情况下,根本不是,因为它是 2^N)。你必须从下面接近它。它确实也会导致比预期结果少一(因为 while 循环中的一检查会减少 dbl)。它取决于执行顺序,如果在评估左侧之前或之后进行减量(据我所知,这是未定义的)。如果是前者,它将永远为真并永远循环。 可能表示 2^53=9,007,199,254,740,992 某处。 这很难反驳!不错的实验 使用while (dbl + 1 != dbl) dbl++; 的一个弱点是dbl + 1 != dbl 可以使用long double 数学进行评估 - 考虑FLT_EVAL_METHOD == 2。这可能会以无限循环结束。【参考方案3】:

***在相同的上下文中有这样的说法,并带有指向IEEE 754的链接:

在典型的计算机系统上,“双精度”(64 位)二进制浮点数的系数为 53 位(其中一个是隐含的)、11 位的指数和一个符号位。

2^53 刚好超过 9 * 10^15。

【讨论】:

@Steve Jessop 或多或少,这确实是我要说的。我还遇到了没有 FPU 的硬件系统仍然需要符合 IEEE 标准,因此如果我 8 个月后回到这里并需要相同的信息,那么“典型系统”的东西并不能真正帮助我我的基于 68K 的微控制器(假设它没有 FPU……我不记得了)。 @San Jacinto - “这没用”过于苛刻。答案非常有用,只是不如它包含典型计算机系统确实使用 IEEE 754 表示的评论那么有用。 @Stephen C. Steel,实际上你是对的。在我的情况下,稍后再回到这个问题并寻找 IEEE 最大值,对于什么是“典型系统”是不可能模棱两可的,但除了这个抱怨之外,答案仍然有优点。【参考方案4】:

IEEE 754 double(64 位)可以表示的最大整数与该类型可以表示的最大值相同,因为该值本身就是一个整数。

这表示为0x7FEFFFFFFFFFFFFF,它由以下部分组成:

符号位 0(正)而不是 1(负) 最大指数0x7FE(2046 表示减去偏差后的 1023)而不是0x7FF(2047 表示NaN 或无穷大)。 最大尾数0xFFFFFFFFFFFFF,即52位全1。

在二进制中,该值是隐含的 1,后跟尾数的 52 个 1,然后是指数的 971 个零 (1023 - 52 = 971)。

确切的十进制值是:

179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368 P>

这大约是 1.8 x 10308

【讨论】:

它可以表示的最大值与它和零之间的所有值都可以连续表示吗? @AaronFranke 该问题并未询问连续表示,但该不同问题的答案已包含在此处的大多数其他答案中,甚至被错误地作为实际答案给出。它是 2⁵³(2 的 53 次方)。【参考方案5】:

您需要查看尾数的大小。一个 IEEE 754 64 位浮点数(有 52 位,隐含加 1)可以精确表示绝对值小于或等于 2^53 的整数。

【讨论】:

它也可以精确地表示 2^53 :-)【参考方案6】:

1.7976931348623157 × 10^308

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

【讨论】:

这个答案加上引用会更好。 @Carl 好吧,如果整数在左边有零,那么它会被精确存储。 @all you downvoters: 1.7976931348623157 × 10^308 一个精确的整数。你们都需要参加补习数学课吗?? 在讨论这个无可救药的沉没答案时,我们只关注语义。诚然,该数字可以准确表示,从而满足问题的字母。但我们都知道,它是一个有惊无险的海洋中的一个精确的小岛,我们中的大多数人都正确地把这个问题插入到了“最大的数字,超过这个数字就会消失”。啊,CompSci 是一门精确的科学,这不是很好吗? :) @DanMoulding 1.7976931348623157 × 10^308 是一个精确的整数,但我很确定这个特定的整数不能精确地存储在双精度数中。【参考方案7】:

确实,对于 64 位 IEEE754 double,可以精确表示 9007199254740992 == 2^53 以内的所有整数。

不过,还值得一提的是,4503599627370496 == 2^52 以外的所有可表示数字都是整数。 超过 2^52 后,测试它们是否为整数就变得毫无意义,因为它们都被隐式四舍五入到附近的可表示值。

在 2^51 到 2^52 范围内,唯一的非整数值是以“.5”结尾的中点,这意味着计算后的任何整数测试都必须预期产生至少 50% 的错误答案。

在 2^51 以下我们也有“.25”和“.75”,因此将一个数字与其四舍五入的对应数字进行比较以确定它是否是整数开始有意义。

TLDR:如果要测试计算结果是否可能是整数,请避免使用大于 2251799813685248 == 2^51 的数字

【讨论】:

【参考方案8】:

正如其他人所指出的,我将假设 OP 要求最大的浮点值,这样所有小于自身的整数都可以精确表示。

您可以使用float.h 中定义的FLT_MANT_DIGDBL_MANT_DIG 来不依赖显式值(例如,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

【讨论】:

以上是关于可以存储在 double 中的最大整数的主要内容,如果未能解决你的问题,请参考以下文章

Java之大数加减乘除——构建类

计算浮点值以将整数乘以产生小于 1 的最大数

模板整理~~~~~大整数乘法

在 O(n) 时间内找到数组中的 10 个最大整数

如何实现大整数相加

java中整数过大怎么办