浮点数和双精度变量的比较

4

可能重复:
float和double之间的区别
用浮点文字比较时输出奇怪的结果

我正在使用Visual C++ 6.0,在程序中比较float和double变量。例如,对于这个程序:

#include<stdio.h>
int main()  
{    
    float a = 0.7f;
    double b = 0.7; 
    printf("%d %d %d",a<b,a>b,a==b);
    return 0;
 }  

我得到了输出为1 0 0

而对于

#include<stdio.h>
int main()  
{    
    float a = 1.7f;
    double b = 1.7; 
    printf("%d %d %d",a<b,a>b,a==b);
    return 0;
 }  

我得到了 0 1 0 作为输出。
请告诉我为什么我会得到这些奇怪的输出,是否有任何方法可以在同一处理器上预测这些输出。还有,在 C 中如何比较两个变量?

5
由于已知的精度和四舍五入问题,你永远不应该将浮点数值进行相等比较。此外,这篇文章是多篇文章中的一个复制品——很快就会找到其中一篇。 - Péter Török
5
数百个“浮点数是否有缺陷?”问题的副本……读完那些问题,直到你明白浮点数本质上是不准确的 - user395760
2
@delnan: 我不会把浮点数本身描述为本质上不准确的。我会将从十进制值转换为二进制浮点值的过程描述为固有的损失。 - Jon Skeet
1
相关内容:http://stackoverflow.com/questions/2743718/when-is-aa-true/2743780#2743780 :) - N 1.1
1
@delnan:你认为整数也不准确吗?毕竟,它们不能表示所有数字。将5除以2,您将在整数算术中得到2,而不是2.5-但没有人说整数不准确,他们只是了解可能值的集合。我认为鼓励对二进制浮点值的这种理解水平比随意使用“不准确”一词更好。 (还有一个问题:您是否认为.NET中的System.Decimal等十进制浮点类型是“不准确”的?) - Jon Skeet
显示剩余7条评论
4个回答

8

这与计算机中浮点数和双精度数的内部表示方式有关。计算机使用二进制存储数字,即基数为2。将十进制数存储为二进制数时,可能会出现重复数字,并且计算机存储的“确切”值并不相同。

比较浮点数时,通常使用一个epsilon来表示值的小变化。例如:

float epsilon = 0.000000001;
float a = 0.7;
double b = 0.7;

if (abs(a - b) < epsilon)
  // they are close enough to be equal.

9
错了,你应该使用fabs。 - user411313

2

1.7d和1.7f很可能是不同的值:一个是在double表达式中可接近于绝对值1.7的最近值,而另一个是在float表达式中可接近于绝对值1.7的最近值。

为了更易理解,想象你有两种类型,shortDecimal和longDecimal。shortDecimal是3个有效数字的十进制值。longDecimal是5个有效数字的十进制值。现在想象你有一种方法来表示圆周率,并将其赋值给shortDecimal和longDecimal变量。短值将是3.14,长值将是3.1416。这两个值并不相同,即使它们都是在各自类型中最接近可表示圆周率的值。


@Hans:发布后问题已更改。最初是打印ab(几乎;实际上是ab,我认为这是a,b的错别字;结果只是未格式化的代码,使一切变得不清楚)。将进行编辑。 - Jon Skeet
@Shynthriir:看一下编辑前的问题... - Jon Skeet
1
抱歉,我知道一定有原因。 - Anthony

1

1.7是十进制数。在二进制中,它具有非有限表示。

因此,1.7和1.7f不同。

启发式证明:当您将位向左移动(即乘以2)时,如果二进制表示“有限”,则最终将成为整数。

但是在十进制中,将1.7乘以2,再次乘以2:您只会得到非整数(小数部分将在.4.8.6.2之间循环)。因此,1.7不是2的幂的总和。


0

你不能将浮点变量进行相等比较。原因是十进制小数被表示为二进制小数,这意味着会有精度损失。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接