浮点值可以加到零和吗? [复制]

Posted

技术标签:

【中文标题】浮点值可以加到零和吗? [复制]【英文标题】:Can float values add to a sum of zero? [duplicate] 【发布时间】:2011-12-17 10:27:29 【问题描述】:

可能重复:Most effective way for float and double comparison

我有两个值(浮点数),我试图将它们加在一起并取平均值。我遇到的问题是,这些值有时会加起来为零,因此不需要对它们进行平均。

我所处的情况具体包含值“-1”和“1”,但当加在一起时,我得到的值是“-1.19209e-007”,显然不是 0。有这方面的信息吗?

【问题讨论】:

你永远不能测试浮点值是否相等(就像你在这里所做的那样,用0检查是否相等)。谷歌搜索(甚至在这里搜索)会产生很多结果。 Uhmmm (a - a) / 2,如果 a 为 1,则为 0。总是。如果我们考虑舍入误差,它也不能产生除零以外的浮点数。你确定这是问题所在? @SalvatorePreviti:不正确。 (a-a) 并不总是给浮点数 0,因为当寄存器中的浮点数存储到内存中时会发生舍入。 @MooingDuck 但肯定(1.+ -1.) 将始终完全为零,因为1.-1. 都可以精确表示(通常)。 @Rob 这些值表示正在摄取的文件中的 x 坐标值。在这种情况下,它们正好是 -1 和 1,但是存储在浮点数据类型中,因为它们并不总是这些值。 【参考方案1】:

至少马上,这听起来像是典型的浮点不精确。

处理它的常用方法是将数字四舍五入到正确的有效数字位数。在这种情况下,您的平均值为-1.19209e-08(即0.00000001192)。到(比如说)六或七位有效数字,那 零。

【讨论】:

这听起来不像典型的浮点不精确。在这种情况下,-11 都可以精确表示,添加它们应该得到0 @JamesKanze:如果它们真的是 1 和 -1,那将是真的。我的猜测(我可能应该说)是 1 和/或 -1 是以前的一些计算的结果,从数学上看应该得到这个数字,但由于四舍五入只接近它。跨度> 这些值是特定网格中的最小和最大 x 坐标值。这些值是从文件中提取的并存储在浮点数组中。接下来,我使用 min/max 函数对所有 x 值进行比较,以确定最大值和最小值。在尝试对它们进行平均后,我遇到了这个问题。 Evan:当您从流中读取浮点数时,即使它们可以精确表示,值也可能不准确。 @MooingDuck 如果可以准确表示该值,并且从流中读取时的结果不准确,那么这是库中的错误。准确读取的算法是众所周知的。【参考方案2】:

将所有数字的总和除以您的计数。在您进行打印、报告比较或您正在做的任何事情之前,将您的答案四舍五入。

【讨论】:

【参考方案3】:

再次,对此进行一些搜索,但这是基本解释...

计算机以 2 为底而不是以 10 为底来近似浮点数。这意味着,例如,0.2(当转换为二进制时)实际上是 0.001100110011 ...永远。由于计算机不能永远添加这些,它必须近似它。

由于这些近似值,我们失去了计算的“精度”。因此“单”和“双”精度浮点数。这就是为什么您从不测试浮点数实际上为 0 的原因。相反,您测试是否低于您想要用作零的某个阈值。

【讨论】:

抱歉,测试0.0 的浮点值是有效且频繁的操作。 可能是,但确实不应该这样做。经过很多(如果有的话)处理浮点数而不是简单的加法或减法(即使那样可能会导致问题),那么“零”几乎可以显示为任何任意小的数字。 如果您知道自己在做什么,则不会。在某些情况下,与0.0 进行比较(或更一般地,使用==!= 进行比较)是有效的,而在某些情况下则不是。没有绝对的规则;您必须了解机器浮点的实际工作原理,并据此进行判断。【参考方案4】:

我很抱歉,但这对我来说没有意义。 两个浮点值,如果它们完全相同但符号相反,相减将始终产生 0。这就是浮点运算的工作原理。

float a = 0.2f;
float b = -0.2f;
float f = (a - b) / 2;
printf("%f %d\n", f, f != 0); // will print out 0.0000 0

如果编译器不优化代码,也将始终为 0。 如果 a 和 b 具有相同的值但符号相反,则无需考虑任何类型的舍入误差!即如果a的高位为0,b的高位为1,其他位相同,则结果不能为0。

但如果 a 和 b 稍有不同,当然,结果可以是非零的。

避免这种情况的一种可能解决方案是使用公差...

float f = (a + b) / 2;

if (abs(f) < 0.000001f)
    f = 0;

我们正在使用一个简单的容差来查看我们的值是否接近于零。

一个很好的示例代码来说明这一点......

int main(int argc)

    for (int i = -10000000; i <= 10000000 * argc; ++i)
    
        if (i != 0)
        
            float a = 3.14159265f / i;
            float b = -a + (argc - 1);

            float f = (a + b) / 2;

            if (f != 0)
                printf("%f %d\n", a, f);
        
    
    printf("completed\n");
    return 0;

我在这里使用“argc”作为强制编译器不优化我们的代码的技巧。

【讨论】:

它们一定是不同的,但我无法区分它们。 这也让我感到困惑,因为 +1 和 -1 可以精确地以浮点格式表示,总和应该正好为 0,除非 1 和 -1 本身不精确(例如如果它们是一些小数的总和)。哦,好吧,问题现在已经解决了,SO 霸主无论如何都不会容忍讨论这些数字是如何产生的,因为它不会以回答问题的形式 =) +1 + -1 = 0 :) 使用 int、float、double。所以我不知道他为什么这么说:) @SamSkuce:这取决于它们是如何设置的。他说它们是从文件中读取的,这意味着它们必须由字符组合而成,这意味着涉及数学,这意味着存在舍入错误的空间。

以上是关于浮点值可以加到零和吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

我可以对浮点表示法错误做些啥? [复制]

如何在python中对具有浮点值的列表进行排序? [复制]

x64 浮点混合

Java中浮点除法中的严重数字损坏? [复制]

转换应该是数据框列中浮点数列表的字符串? [复制]

如何从浮点值Swift 3中删除前导零