浮动比较给出不同的结果

发布于 2024-12-07 02:35:43 字数 495 浏览 1 评论 0原文

看下面两个代码,告诉我答案差异很大的原因。

#include<stdio.h>
int main() {
    float a = 0.9;
    if(a<0.9)
        printf("hi"); // This will be the answer
    else
        printf("bye");
    return 0;
}

如果我们将 0.9 更改为 0.8,则会打印 else 的语句:

#include<stdio.h>
int main() {
    float a = 0.8;
    if(a<0.8)
        printf("hi");
    else
        printf("bye");//this will be the answer
    return 0;
}

那么,为什么当我们只更改一位数字时,输出会发生变化呢?

Look at the following two codes, and tell me the reason why answers vary a lot.

#include<stdio.h>
int main() {
    float a = 0.9;
    if(a<0.9)
        printf("hi"); // This will be the answer
    else
        printf("bye");
    return 0;
}

And if we change 0.9 to 0.8, then else's statement is printed:

#include<stdio.h>
int main() {
    float a = 0.8;
    if(a<0.8)
        printf("hi");
    else
        printf("bye");//this will be the answer
    return 0;
}

So why this output changes when we just change a single digit?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

老子叫无熙 2024-12-14 02:35:43

此错误是由于浮点精度造成的,并且因为您正在将 float 类型与 double 值进行比较。尝试将其与浮点文字进行比较:if(a<0.8f)

我建议您阅读相应的维基百科文章,它详细解释了您的错误发生的原因。

This error is due to floating point accuracy and because you are comparing a float type with a double value. Try to compare it versus floating point literals: if(a<0.8f)

I suggest you read the according wikipedia article, it explains in detail why your error happens.

郁金香雨 2024-12-14 02:35:43

文字 0.90.8 的类型为 double。由于这两个值无法准确表示,因此它们实际上是 0.9000000000000000222...0.8000000000000000444...

当存储在float(单精度)变量a中时,它们将被转换为单精度并且变得更加不准确:0.89999997...和<代码>0.8000000119...。

为了与文字 double 值进行比较,它们会被转换回 double 并保留更不准确的值。

从上面的数字可以看出,0.90.8 的比较结果不同。

所有这些都假设您的平台具有 IEEE754 浮点,这很可能是这种情况。

您可以在 www.binaryconvert.com 上查看数字的单/双表示形式。

The literals 0.9 and 0.8 have type double. Since both values cannot be represented exactly, they will in fact be 0.9000000000000000222... and 0.8000000000000000444....

When stored in the float (single precision) variable a they will be converted to single and become even more inaccurate: 0.89999997... and 0.8000000119....

For the comparison with the literal double value they are converted back to double retaining the more inaccurate value.

As you can see from the numbers above, the comparison yields different results for 0.9 and 0.8.

All this is assuming your platform has IEEE754 floats which is most probably the case.

You can see single/double representations of numbers at www.binaryconvert.com.

可爱咩 2024-12-14 02:35:43

您必须知道浮点是如何工作的。

浮点数使用 2 的幂表示,每个数字用于表示 2^-x,其中 X 是第 n 位数字。

例如,0.011(二进制)将是 2^-2 + 2^-3,即 0.25 + 0.125 = 0.375

现在尝试代表0.9。你有麻烦了,因为没有二的幂可以代表它。以 32 位和 64 位机器表示的值将给出略小于 0.9 的结果,而对于 0.8,结果是精确的并且可以用 2 的幂表示

您可以通过打开 python 提示符来尝试此操作。尝试输入几个数字,最终会以 ...99999999 结尾。

You have to know how floating points works.

Floating points are represented by using powers of two, each digit is used to represent 2^-x where X is the n-th digit.

For example, 0.011 (binary) would be 2^-2 + 2^-3, which is 0.25 + 0.125 = 0.375

Now try to represent 0.9. You are in trouble, since no power of two to represent it. The value this is represented in 32-bits and probably 64-bits machines will give a result slightly smaller than 0.9, whereas for 0.8 the result is precise and representable by powers of two.

You can try this out by opening a python prompt. Try and type a few numbers, eventually one will end with ...99999999.

北方的韩爷 2024-12-14 02:35:43

根据C标准:

6.3.1.5 实数浮动类型

1) 当 float 提升为 double 或 long double 时,或者 double 被提升时
提升为long double,其值不变。

2) 当 double 降级为 float 时,long double 降级为 double
或浮点数,或以更高精度和范围表示的值
比其语义类型(参见 6.3.1.8)所要求的显式
转换为其语义类型,如果要转换的值可以是
完全在新类型中表示,它没有改变。如果值
被转换的值在可以表示的范围内,但是
无法准确表示,结果要么是最接近的更高值
或最接近的较低可表示值,在一个中选择
实现定义的方式。如果被转换的值在外部
可以表示的值的范围,行为未定义。

该标准可在此处找到

According to the C Standard:

6.3.1.5 Real floating types

1) When a float is promoted to double or long double, or a double is
promoted to long double, its value is unchanged.

2) When a double is demoted to float, a long double is demoted to double
or float, or a value being represented in greater precision and range
than required by its semantic type (see 6.3.1.8) is explicitly
converted to its semantic type, if the value being converted can be
represented exactly in the new type, it is unchanged. If the value
being converted is in the range of values that can be represented but
cannot be represented exactly, the result is either the nearest higher
or nearest lower representable value, chosen in an
implementation-defined manner. If the value being converted is outside
the range of values that can be represented, the behavior is undefined.

The standard can be found here.

情栀口红 2024-12-14 02:35:43

这是由于舍入错误造成的,要查看您正在使用的值,请在 if 之前插入 printf:

printf("a=%f\n", a);

This is due to rounding errors, to see the value of that you are using insert a printf before the if:

printf("a=%f\n", a);
红尘作伴 2024-12-14 02:35:43

首先,正如其他人提到的,在使用 float 时使用诸如 0.8f 之类的值。

此外,由于 FPU 中此操作的精度,您应该避免进行浮点 == 比较。对我来说最有效的方法是定义一个边距,比如说 1e-6f (或者根据您的应用程序需要的精度),而不是这样:

if (LHS == RHS)

您可以编写:

if (LHS-RHS < MARGIN && RHS-LHS < MARGIN)

您可以编写一个函数(如果你是 c++ 粉丝)或宏(如果你是 ac 粉丝(这里是 -1s))会为你完成此操作。

First of all, as others mentioned, use values like 0.8f when working with floats.

Also, floating point == comparison is something you would want to avoid because of the precision of this operation in the FPU. What always worked best for me, was to define a margin, let's say 1e-6f (or the precision you need based on your application) and instead of this:

if (LHS == RHS)

you write:

if (LHS-RHS < MARGIN && RHS-LHS < MARGIN)

You could write a function (if you are a c++ fan) or macro (if you are a c fan (here comes the -1s)) that does this for you.

妳是的陽光 2024-12-14 02:35:43

试试这个:

用“if(a<0.9f)”代替“if(a<0.9)”进行比较

Try this:

Instead of "if(a<0.9)" compare using "if(a<0.9f)"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文