当前位置: 首页 > 知识库问答 >
问题:

(0.1 0.2) == 0.3是真是假?

印成天
2023-03-14

我对浮点数有一个基本的了解,并且正在阅读这篇文章,其中说:

0.1 0.2:这等于0.3,但在浮点数中:(0.1 0.2) == 0.3为false。这是因为0.1、0.2和0.3不能精确地表示在基2浮点数中。

根据浮点数的性质,这是正确的,但我编写了一个简单的程序来测试:

float a = 0.1;
float b = 0.2;

if(a+b == 0.3)
{
  printf("true");
} else 
{
  printf("false");
}
// result is true

但是输出实际上是true。以下是我的两个问题:

>

  • 我想发生的是,因为C使用了从四舍五入到五舍五入的模式,所以在四舍五入之后,它恰好是真的,我的理解正确吗?

    如果我的理解是正确的,那么一定有一些指定的浮点数在这种情况下不会是真的,因为舍入仍然有很小的可能性会失败。所以这一定是某种组合

    float a = ...;
    float b = ...;
    if(a+b == XXX)  // where XXX is the "intuitive" sum of a and b
    {
      printf("true");
    } else 
    {
      printf("false");   
    }
    
    //result is false now
    

    我的理解正确吗?

  • 共有3个答案

    楚岳
    2023-03-14

    在数学意义上,0.1 0.2==0.3总是正确的

    在浮点意义上,0.1 0.2==0.3仅当error表示0.1错误表示0.2==error表示0.3

    我相信你知道误差取决于值及其大小。因此,在少数情况下,错误对齐使得浮点数似乎适用于相等,但一般情况下,这种比较通常是错误的,因为它们无法解释错误。

    要编写强浮点代码,您需要研究测量理论,以及如何在整个公式中传播测量误差。这也意味着您必须将C类型(位比较)相等替换为“错误范围内的相等”。

    请注意,您无法构建一个能够完美地自动处理程序中错误的系统,因为要做到这一点,将需要一个精确的有限大小存储方法来存储任何分数的可能无限重复的数字。因此,通常使用误差估计,并且通常在针对所涉及的值进行调整的近似边界内对结果进行比较。

    很快就会意识到,虽然您的程序是正确的,但您不能信任该技术,因为该技术通常不会返回正确的值。

    华君浩
    2023-03-14

    通常,当您编写以下语句时,所有浮点右值都声明双精度(例如0.5、11.332、8.9等):

    float a = 0.1;
    float b = 0.2;
    
    if(a+b == 0.3)
      printf("true");
    else
      printf("false");
    

    它的计算结果为0.1 0.2=0.3,这没关系,但在右侧,0.3的工作方式与您预期的不同,正如前面提到的,默认情况下,它被声明为double

    因此,编译器试图比较值:

    0.3 == 0.2999999999999999889
    

    这显然是不平等的。

    为了解决这个问题,您需要附加一个后缀来表示您试图使用浮点值的编译器。

    请尝试以下方法:

    (a + b == 0.3F)
    

    Ff表示值为浮点

    不幸的是,你不能用double做同样的事情。为了证明这一点,您可以编写以下代码:

    #include <iomanip>
    .
    .
    .
    cout << setprecision(20) << 0.1 << endl;
    cout << setprecision(20) << 0.2 << endl;
    cout << setprecision(20) << 0.3 << endl;
    cout << setprecision(20) << (0.1 + 0.2) << endl;
    

    您将了解到,将显示的所有上述值将具有不同的值:

    0.10000000000000000555 // 0.1
    0.2000000000000000111  // 0.2
    0.2999999999999999889  // 0.3 -------- NOTE
    0.30000000000000004441 // 0.1 + 0.2 -- NOTE
    

    现在,比较NOTE的值。它们也是不平等的。

    因此,0.299999999999889和0.300000000000000004441的比较失败,您将不惜任何代价得到False。

    苏君昊
    2023-03-14

    对于您的程序,我得到的是false,而不是您在问题中指出的true。(0.3是一个doubleliteral,所以我猜当您在本地测试它时,您使用了一个float变量而不是0.3literal。)如果实际使用float==0.3f而不是==0.3),则会得到true作为输出,因为恰好使用float0.1 0.2==0.3

    但是,最基本的一点仍然是,float(单精度)和double(双精度)使用的IEEE-754二进制浮点计算速度非常快,对很多事情都很有用,但对某些值来说本质上是不精确的,因此会出现这种问题。使用float,对于0.1 0.2==0.3,您会得到true,但是对于0.1 0.6==0.7,您会得到false

    #include <stdio.h>
    
    int main() {
        printf("%s\n", 0.1f + 0.6f == 0.7f ? "true" : "false"); // prints false
        //             ^^^^−−−^^^^−−−−^^^^−−− `float` literals
        return 0;
    }
    

    这个问题的著名的0.1 0.2 == 0.3版本碰巧是

    #include <stdio.h>
    
    int main() {
        printf("%s\n", 0.1 + 0.2 == 0.3 ? "true" : "false"); // prints false
        //             ^^^−−−^^^−−−−^^^−−− `double` literals
        return 0;
    }
    
     类似资料:
    • 问题内容: 例如,可以将其用于生成一次性填充密钥吗? 另外,它的来源是什么,如何将其用于生成 x 和 y 之间的随机数? 问题答案: 在这个宇宙中,唯一可以真正考虑的是基于量子效应的宇宙。常见的例子是放射性衰变。对于某些原子,您只能确定其半衰期,但不能确定下一个原子核会破裂。 关于-取决于实现。在Linux中,它用作熵源: Linux内核根据键盘时序,鼠标移动和IDE时序生成熵,并通过特殊文件/

    • 本文是随写随即同步到Github上,因此在行文中难免会遗漏引用。本文绝大部分内容应是直接承出我笔,但是也不定会有他山之石。所有指涉内容我会尽量以引号框记,或在上下文和边角注记中标示,如有遗漏烦请不吝指出。 全文所有为我所撰写的部分,作者均保留所有版权。如果有需要转帖或引用,还请注明出处并告知于我。

    • 0.3.11Released: Sun Oct 14 2007 orm [orm] ¶ 使用join()在两个不同的M2M表上添加了从a->b的连接检查。这会在0.3中引发错误,但在使用别名时,可能在0.4中出现错误。 References: #687 [orm] ¶ 修复了在session.merge()中引发错误的小异常 [orm] ¶ 修正了当映射器链接到一个表没有pk列的联接时,无法检测到

    • 本文向大家介绍"ABCD四个人里有2个人只说真话,有2个人只说假话,其中A说他是说真话的,B说他是说真话的,C说B说的是真的,D说C说的是假话,请问ABCD四个人说话分别是真是假?"相关面试题,主要包含被问及"ABCD四个人里有2个人只说真话,有2个人只说假话,其中A说他是说真话的,B说他是说真话的,C说B说的是真的,D说C说的是假话,请问ABCD四个人说话分别是真是假?"时的应答技巧和注意事项,

    • 下面的代码将输出“true”,这意味着Array()为true。在Python中,list()为False,这是否只是因为语言设计者的偏好?

    • 问题内容: 在此处的示例Redigo Docs forPool中,redis池在funcmain中设置为全局变量。这是一种洁净的做事方式吗?您是否应该真正在左右使用全局变量,或者是否有更好,更优选的方法来完成同一件事? 问题答案: 我看到的唯一其他解决方案例如在“将上下文传递给接口方法”中是: 创建一个接受嵌入式上下文和我们的类型的,并且由于,我们仍然满足该接口。 在您的情况下,将包括和功能。