9

是否存在这样的情况:如果将它们比较为 FLOAT,则equals()两个浮点值之间的比较 () 会返回falseDOUBLEtrue如果将它们比较为 FLOAT 则返回?

作为我的小组项目的一部分,我正在编写一些程序来比较任何给定类型的两个数值。我必须总共处理 4 种类型:doublefloat和. 所以我想将and组合成一个函数,也就是说,我只需将 any转换为并进行比较。intlongdoublefloatfloatdouble

这会导致任何不正确的结果吗?

谢谢。

4

7 回答 7

15

如果您将双精度数转换为浮点数并且它们之间的差异超出了浮点类型的精度,您可能会遇到麻烦。

例如,假设您有两个双精度值:

9.876543210
9.876543211

并且浮点数的精度只有六位十进制数字。这意味着两个float值都是9.87654,因此相等,即使双精度值本身不相等。

但是,如果您正在谈论将浮点数转换为双精度数,那么相同的浮点数应该给您相同的双精度数。如果浮点数不同,则额外的精度将确保双精度数也不同。

于 2012-04-10T04:22:17.993 回答
9

只要您没有在比较中混合提升的浮点数和本机计算的双精度数,您应该没问题,但要小心:

比较浮点数(或双精度数)的相等性很困难 -请参阅这个冗长但出色的讨论

以下是一些亮点:

  1. ==由于浮点格式精度有限的问题,您不能使用

  2. float(0.1) 和 double(0.1) 分别是不同的值(0.100000001490116119384765625 和 0.1000000000000000055511151231257827021181583404541015625)。在您的情况下,这意味着比较两个浮点数(通过转换为双精度数)可能没问题,但是如果要将浮点数与双精度数进行比较,请小心。

  3. 通常使用 epsilon 或较小的值来进行相对比较(如果浮点数 a 和 b 被认为相等a - b < epsilon)。在 C 中,float.hFLT_EPSILON正是为此目的而定义的。a但是,这种类型的比较在两者都非常小或b都非常大的情况下不起作用。

  4. 您可以通过使用相对于大小的 a-and-b epsilon 来解决此问题,但在某些情况下(例如与零的比较),这会失效。

  5. 您可以比较浮点数的整数表示,以找出它们之间有多少可表示的浮点数。这就是 JavaFloat.equals()所做的。这称为 ULP 差异,即“最后位置的单位”差异。它通常很好,但在与零比较时也会崩溃。

文章总结:

知道你在做什么

没有银弹。你必须明智地选择。

  • 如果您要与零进行比较,那么基于相对 epsilon 和 ULP 的比较通常是没有意义的。您需要使用绝对 epsilon,其值可能是 FLT_EPSILON 的一些小倍数以及计算的输入。也许。
  • 如果您要与非零数进行比较,那么基于相对 epsilon 或 ULP 的比较可能是您想要的。您可能需要一些小的 FLT_EPSILON 倍数作为您的相对 epsilon,或者一些少量的 ULP。如果您确切知道要比较的数字,则可以使用绝对 epsilon。
  • 如果您要比较两个可能为零或非零的任意数字,那么您需要厨房水槽。祝你好运和上帝的速度。

所以,回答你的问题:

  • 如果您将 s 降级doublefloats,那么您可能会失去精度,并错误地将两个不同double的 s 报告为相等(正如paxdiablo指出的那样。)
  • 如果您将相同float的 s 升级为,那么除非您将 a与 a进行比较,否则double增加的精度不会成为问题(假设您的浮点数为 1.234,并且您只有 4 位小数的精度,那么双精度 1.2345 MIGHT表示与浮点数相同的值。在这种情况下,您最好以 的精度进行比较,或者更一般地,在比较中最不准确的表示的错误级别进行比较)。floatdoublefloat
  • 如果您知道要与之比较的数字,则可以遵循上面引用的建议。
  • 如果您要比较任意数字(可能为零或非零),则无法在所有情况下都正确比较它们 - 选择一个比较并了解其局限性。

一些实际的考虑(因为这听起来像是一个任务):

  • 大多数人提到的 epsilon 比较可能很好(但在文章中包括对局限性的讨论)。如果您打算将双精度数与浮点数进行比较,请尝试在浮点数中进行,但如果没有,请尝试在双精度中进行所有比较。更好的是,在double任何地方都使用 s。

  • 如果您想完全完成作业,请在比较浮点数时记录问题以及您选择任何特定比较方法的理由。

于 2012-04-10T05:54:40.467 回答
2

我完全不明白你为什么要这样做。==运营商已经满足了双方所有可能的类型,在相关语言标准中已经规定了类型强制和扩大的广泛规则。您所要做的就是使用它。

于 2012-04-10T04:20:44.163 回答
2

我可能不是在回答 OP 的问题,而是在回答一些或多或少需要澄清的模糊建议。

比较两个浮点值是否相等是绝对可能的,并且可以做到。如果类型是单精度或双精度通常不太重要。

话虽如此,导致比较本身的步骤需要非常小心并彻底理解浮点的注意事项、为什么和为什么不。

考虑以下 C 语句:

result = a * b / c;
result = (a * b) / c;
result = a * (b / c);

在大多数幼稚的浮点编程中,它们被视为“等效”,即产生“相同”的结果。在浮点的现实世界中,它们可能是。或者实际上,前两个是等价的(因为第二个遵循 C 评估规则,即从左到右具有相同优先级的运算符)。第三个可能等同于也可能不等同于第一个twp。

为什么是这样?

“a * b / c”或“b / c * a”可能导致“不精确”异常,即中间或最终结果(或两者)不精确(以浮点格式表示)。如果是这种情况,结果将或多或少有些微妙的不同。这可能会或可能不会导致最终结果适合进行相等比较。意识到这一点并一次单步地执行一个操作——注意中间结果——将允许耐心的程序员“击败系统”,即为几乎任何情况构建一个高质量的浮点比较。

对于其他人来说,忽略浮点数的相等比较是很好的、可靠的建议。

这真的有点讽刺,因为大多数程序员都知道整数数学在各种情况下会导致可预测的截断。当谈到浮点时,几乎每个人都或多或少地对结果不准确感到震惊。去搞清楚。

于 2012-04-13T20:19:17.190 回答
1

只要相等性测试涉及增量,您就应该可以进行该转换。

例如:abs((double) floatVal1 - (double) floatVal2) < .000001应该工作。

针对问题更改进行编辑

不,你不会。以上依然成立。

于 2012-04-10T04:21:30.063 回答
1

对于float f和double d的比较,可以计算f和d的差值。如果 abs(fd) 小于某个阈值,您可以认为等式成立。根据您的应用要求,这些阈值可以是绝对的或相对的。这里有一些很好的解决方案。我希望它有帮助。

于 2012-04-10T04:57:48.897 回答
0

如果我将 2 个浮点数提升为双倍并进行 64 位比较而不是 32 位比较,我会得到不正确的结果吗?

不。

如果您从两个浮点数开始,可以是浮点变量 (float x = foo();) 或浮点常量 (1.234234234f),那么您当然可以直接比较它们。如果将它们转换为 double 然后比较它们,那么结果将是相同的。

这是有效的,因为 double 是浮点数的超集。也就是说,可以存储在 float 中的每个值都可以存储在 double 中。指数和尾数的范围都增加了。有数十亿个值可以存储在双精度型但不能存储在浮点型中,但有零个值可以存储在浮点型中但不能存储在双精度型中。

正如我在float 比较文章中所讨论的,在 float 或 double 值之间进行有意义的比较可能会很棘手,因为可能会出现舍入错误。但是,将两个数字从 float 转换为 double 并不会改变这一点。所有对 epsilon 的提及(通常但并非总是需要)都与问题完全正交。

另一方面,将 float 与 double 进行比较是疯狂的。1.1(双精度型)不等于 1.1f(浮点型),因为 1.1 都不能精确表示。

于 2016-02-19T17:00:49.863 回答