代码之家  ›  专栏  ›  技术社区  ›  levanovd

C int存储在double中“==”精度问题

  •  9
  • levanovd  · 技术社区  · 15 年前

    下面是简化代码:

    int i = 1;
    double a = i;
    double b = i;
    

    保证了吗 a == b ?

    4 回复  |  直到 15 年前
        1
  •  11
  •   Ian Henry    15 年前

    对。32位整数可以精确表示为64位浮点数。

        2
  •  9
  •   agsamek    15 年前

    保证a==b是真的吗?

    对。这是因为您执行了两次相同的转换,并且考虑到它的确定性行为,不管舍入问题如何,最终都会得到相同的值。

    不过,我们可以将您的问题概括为:

    我们能对32位整数值进行算术运算吗? double 没有精密松动的类型?

    这个问题的答案也是肯定的。

    一个简短的理由是尾数位上的操作(参见 http://en.wikipedia.org/wiki/Significand )如果只有可能,则是精确的;如果是32位整数值,则是可能的。

    长话短说。只要整数值符合尾数部分的52位(参见 http://en.wikipedia.org/wiki/Double_precision )使用double对整数值进行的所有计算将完全正常。

    这是因为你的号码(比如173 0000010101101b 二进制)表示为 1.010110100000b*2^7 ,准确无误。

    尾数上的所有操作都是直接向前的,只要它们适合尾数。整数的四舍五入发生在一个特定操作的结果不适合尾数的时候——例如,你将尾数的40位乘以尾数的40位。当指数大不相同时,浮点运算的舍入也会发生。在这种情况下,即使一个简单的加法操作也会由于马蒂萨的移位而降低精度。

    回到整数编码的双偶除法运算是精确的,只要结果是整数值。所以 4.0/2.0 == 8.0/4.0 也保证是真实的。

    当您的数字不是整数时,问题就开始了。但即使在这种情况下,如果数字是 x/2^y x 适合52位(例如 3/4 5/8 345/1024 )对这些数字的运算也很精确 y 两个操作数可以相等,因此偶数:

    123456789/1024/1024/1024/1024 == 
    (23456789/1024/1024/1024/1024 +
    100000000/1024/1024/1024/1024)
    

    保证是真实的。

    有趣的是,您可以安全地对54位有符号整数执行操作。这是因为在开始处有额外的位,其含义由指数编码,而符号则有额外的位。现在-2^53,在54位有符号整数的情况下,它将是min_int,不适合尾数,但是指数将在尾数充满零的情况下完成这项工作。

        3
  •  3
  •   stakx - no longer contributing Saravana Kumar    15 年前

    是的,可以将(32位)整数存储在 double (64位浮点数),无精度损失。

    但是,一旦您使用 双重的 ,您很可能会引入舍入误差,即精度损失。这些错误很可能很小,因此当您将 双重的 值返回到 int -但是错误是存在的,所以要注意它。

    如何完成: this document ( IEEE Standard 754 Floating Point Numbers by Steve Hollasch) 有关如何将整数存储为浮点值的详细信息。

    总结一下(有些不准确),浮点值由三部分组成:符号位、“分数”部分(称为尾数)和“指数”部分。它们大致如下:

    价值 = 1 符号位 × 分数 ×2 指数

    您可以将整数值存储在 双重的 (52位宽,足以容纳32位整数。“指数”部分可以设置为0,因为它不需要。

        4
  •  -2
  •   Jan Sverre    15 年前

    我打开了Visual Studio,并对其进行了测试。

    这是我的代码:

    int i = 5;
    double t = i;
    double k = i;
    MessageBox.Show((i == t).ToString()); //true
    MessageBox.Show((k == t).ToString()); //true
    i += 5;
    t += 5;
    k = i;
    MessageBox.Show((i == t).ToString()); //true
    MessageBox.Show((k == t).ToString()); //true
    i += (int)Math.Round(5.6);
    t += 5.6;
    t = (int)Math.Round(t);
    k = i;
    MessageBox.Show((i == t).ToString()); //true
    MessageBox.Show((k == t).ToString()); //true
    i = int.MaxValue - 5438;
    t = int.MaxValue - 5438;
    k = i;
    MessageBox.Show((i == t).ToString()); //true
    MessageBox.Show((k == t).ToString()); //true
    i = (int)Math.Round(double.MaxValue);
    t = Math.Round(double.MaxValue);
    k = i;
    MessageBox.Show((i == t).ToString()); //false
    MessageBox.Show((k == t).ToString()); //false
    i = (int)Math.Round(double.MaxValue);
    t = i;
    k = i;
    MessageBox.Show((i == t).ToString()); //true
    MessageBox.Show((k == t).ToString()); //true
    

    结果是两个消息框说的是真的。

    我想结论是:是的,你可以保证这是真的。

    编辑:延长了我的测试时间。唯一返回false的测试是double.maxvalue的测试,但我怀疑您是否会使用这么大的数字。

    推荐文章