Float vs Double
是否存在两个浮点值之间的比较( equals()
)如果将它们比较为DOUBLE
则返回false
但如果将它们作为FLOAT进行比较则返回true
情况?
作为我的小组项目的一部分,我正在编写一些程序来比较任何给定类型的两个数值。 我必须处理4种类型: double
, float
, int
和long
。 所以我想将double
和float
成一个函数,也就是说,我只是将任何float
为double
并进行比较。
这会导致任何不正确的结果吗?
谢谢。
如果你将双精度转换为浮点数并且它们之间的差异超出浮点类型的精度,则可能会遇到麻烦。
例如,假设您有两个双精度值:
9.876543210 9.876543211
并且浮点数的精度只有六位十进制数。 这意味着两个float
值都是9.87654
,因此相等,即使双值本身不相等。
但是,如果你在谈论浮动被投射到双打,那么相同的浮动应该给你相同的双打。 如果浮子不同,额外的精度将确保双打也是不同的。
只要你没有在你的比较中混合推广的花车和原生计算的双打,你应该没问题,但要小心:
比较花车(或双打)的平等是很困难的 – 看这个冗长但很好的讨论 。
以下是一些亮点:
-
您不能使用
==
,因为浮点格式的精度有限 -
float(0.1)和double(0.1)分别是不同的值(0.100000001490116119384765625和0.1000000000000000055511151231257827021181583404541015625)。 在你的情况下,这意味着比较两个浮点数(通过转换为double)可能没问题,但是如果你想要将float与double进行比较,请小心。
-
使用epsilon或小值来进行相对比较是很常见的(如果
a - b < epsilon
浮点数a和b被认为是相等的)。 在C中,float.h为此目的定义了FLT_EPSILON
。 但是,这种类型的比较在a
和b
都非常小或非常大的情况下都不起作用。 -
你可以通过使用缩放相对于大小的a-and-b epsilon来解决这个问题,但在某些情况下会出现这种情况(例如比较为零)。
-
您可以比较浮点数的整数表示 ,以找出它们之间有多少可表示的浮点数。 这就是Java的
Float.equals()
所做的。 这称为ULP差异,用于“最后位置的单位”差异。 它通常很好,但在与零比较时也会崩溃。
文章的结论是:
知道你在做什么
没有银弹。 你必须明智地选择。
- 如果您与零进行比较,那么基于相对epsilons和ULP的比较通常是没有意义的。 您需要使用绝对epsilon,其值可能是FLT_EPSILON的一小部分和计算的输入。 也许。
- 如果您要与非零数字进行比较,那么基于相对epsilons或ULP的比较可能就是您想要的。 你可能想要一些FLT_EPSILON的小倍数用于你的相对epsilon,或者一些少量的ULP。 如果您确切地知道您要比较的数字,则可以使用绝对epsilon。
- 如果您要比较两个可能为零或非零的任意数字,那么您需要厨房水槽。 祝你好运和上帝的速度。
那么,回答你的问题:
- 如果你将
double
s降级为float
s,那么你可能会失去精度,并错误地将两个不同的double
s报告为相等(如paxdiablo指出的那样)。 - 如果要将相同的
float
升级为double
,那么添加的精度将不会成为问题, 除非您将float
与double
进行比较(假设您在浮点数中得到1.234,并且您只有4位十进制数字的精度,那么双1.2345 MIGHT表示与浮点数相同的值。在这种情况下,您可能最好以float
的精度进行比较,或者更一般地,在比较中最不准确的表示的错误级别进行比较)。 - 如果您知道要与之比较的数字,可以按照上面引用的建议进行操作。
- 如果您要比较任意数字(可能是零或非零),则无法在所有情况下正确比较它们 - 选择一个比较并了解其局限性。
一些实际考虑因素(因为这听起来像是作业):
-
大多数人提到的epsilon比较可能很好(但包括对写作中限制的讨论)。 如果您计划将双精度数与浮点数进行比较,请尝试在浮点数中进行,但如果没有,请尝试以双精度进行所有比较。 更好的是,到处都使用
double
s。 -
如果您想完全改变作业,请在比较浮动时包括问题的说明以及选择任何特定比较方法的原因。
我不明白为什么你这样做。 ==
运算符已经满足了双方所有可能的类型,并且已经在相关语言标准中指定了类型强制和扩展的广泛规则。 你所要做的就是使用它。
我可能没有回答OP的问题,而是回应一些需要澄清的或多或少模糊的建议。
比较两个浮点值是否相等绝对是可能的,并且可以完成。 如果类型是单精度或双精度通常不太重要。
已经说过导致比较的步骤本身需要非常小心和彻底了解浮点注意事项,为什么不做。
考虑以下C语句:
result = a * b / c; result = (a * b) / c; result = a * (b / c);
在大多数天真的浮点编程中,它们被视为“等效”,即产生“相同”的结果。 在浮点的现实世界中,他们可能是。 或者实际上,前两个是等价的(因为第二个遵循C评估规则,即从左到右的相同优先级的运算符)。 第三个可能或可能不等于第一个twp。
为什么是这样?
“a * b / c”或“b / c * a”可能导致“不精确”exception,即中间或最终结果(或两者)不精确(可以浮点格式表示)。 如果是这种情况,结果或多或少会略有不同。 这可能会也可能不会导致最终结果适合于平等比较。 意识到这一点,并且一次一步地进行操作 – 注意中间结果 – 将允许患者程序员“击败系统”,即在几乎任何情况下构建高质量的浮点比较。
对于其他人来说,通过浮动数字的平等比较是好的,可靠的建议。
这真的有点讽刺,因为大多数程序员都知道整数数学会在各种情况下产生可预测的截断。 说到浮点,几乎每个人都或多或少地震惊,结果并不准确。 去搞清楚。
只要相等测试涉及delta,你就可以进行转换。
例如: abs((double) floatVal1 - (double) floatVal2) < .000001
应该可以工作。
编辑以响应问题更改
不,你不会。 以上仍然有效。
对于float f和double d之间的比较,可以计算f和d的差值。 如果abs(fd)小于某个阈值,你可以想到等式成立。 根据您的应用要求,这些阈值可以是绝对的或相对的。 这里有一些很好的解决方案。 我希望它有所帮助。
如果我将2个浮点数增加一倍并进行64位比较而不是32位比较,我会得到不正确的结果吗?
没有。
如果你从两个浮点开始,可能是浮点变量(浮点数x = foo();)或浮点常数(1.234234234f),那么你可以直接比较它们。 如果将它们转换为double,然后比较它们,那么结果将是相同的。
这是因为double是一组超级浮点数。 也就是说,可以存储在float中的每个值都可以存储在double中。 指数和尾数的范围都增加了。 有数十亿的值可以存储在double中但不能存储在float中,但是零值可以存储在float中但不能存储在double中。
正如我的浮动比较文章中所讨论的那样,在float或double值之间进行有意义的比较可能很棘手,因为舍入错误可能已经悄悄进入。但是,将这两个数字从float转换为double并不会改变这一点。 所有提到的epsilons(通常但并不总是需要)与问题完全正交。
另一方面, 将浮动与双重比较是疯狂的 。 1.1(一个double)不等于1.1f(浮点数),因为1.1中的1.1都不能精确表示。