关于浮动特征的问题

时间:2017-10-24 21:00:40

标签: c compare precision

Q1:出于什么原因,建议不要像 V1 那样按==!=比较浮点数?
Q2: V2 fabs()的工作方式是否相同,就像我在 V3 中编程一样? 问题3:可以使用(x >= y)(x <= y)吗? Q4:根据维基百科float的精确度在6到9位之间,在我的情况下是7位数。那么它依赖于什么,我float的6到9位数之间的精度是多少?见[1]

[1] 浮动特征

Source: Wikipedia
Type   | Size              | Precision           | Range
Float  | 4Byte ^= 32Bits   | 6-9 decimal digits  | (2-2^23)*2^127
Source: tutorialspoint
Type   | Size              | Precision           | Range
Float  | 4Byte ^= 32Bits   | 6 decimal digits    | 1.2E-38 to 3.4E+38
Source: chortle
Type   | Size              | Precision           | Range
Float  | 4Byte ^= 32Bits   | 7 decimal digits    | -3.4E+38 to +3.4E+38

以下三个代码产生相同的结果,但仍不建议使用第一个变体。

1。变体

#include <stdio.h>    // printf() scanf()
int main()
{
  float a = 3.1415926;
  float b = 3.1415930;

  if (a == b)
  {
    printf("a(%+.7f) == b(%+.7f)\n", a, b);
  }
  if (a != b)
  {
    printf("a(%+.7f) != b(%+.7f)\n", a, b);
  }
  return 0;
}

V1-输出:

a(+3.1415925) != b(+3.1415930)

2。变体

#include <stdio.h>    // printf() scanf()
#include <float.h>    // FLT_EPSILON == 0.0000001
#include <math.h>     // fabs()
int main()
{
  float x = 3.1415926;
  float y = 3.1415930;

  if (fabs(x - y) < FLT_EPSILON)
  {
    printf("x(%+.7f) == y(%+.7f)\n", x, y);
  }
  if (fabs(x - y) > FLT_EPSILON)
  {
    printf("x(%+.7f) != y(%+.7f)\n", x, y);
  }
  return 0;
}

V2-输出:

x(+3.1415925) != y(+3.1415930)

第3。变体:

#include <stdio.h>    // printf() scanf()
#include <float.h>    // FLT_EPSILON == 0.0000001
#include <stdlib.h>   // abs()
int main()
{
  float x = 3.1415926;
  float y = 3.1415930;

  const int FPF = 10000000;   // Float_Precission_Factor
  if ((float)(abs((x - y) * FPF)) / FPF < FLT_EPSILON)   // if (x == y)
  {
    printf("x(%+.7f) == y(%+.7f)\n", x, y);
  }
  if ((float)(abs((x - y) * FPF)) / FPF > FLT_EPSILON)   // if (x != y)
  {
    printf("x(%+.7f) != y(%+.7f)\n", x, y);
  }
  return 0;
}

V3-输出:

x(+3.1415925) != y(+3.1415930)

我很感激任何帮助,链接,参考和提示!

3 个答案:

答案 0 :(得分:2)

使用浮点运算时,几乎每一步都可能引入一个小的舍入误差。将源代码中的十进制数转换为浮点格式?除非数字完全可以表示,否则会出现一个小错误。添加两个号码?它们的精确总和通常具有比浮点格式更多的位,因此必须进行舍入以适应。乘法和除法也是如此。拿一个平方根?结果通常是不合理的,不能以浮点格式表示,因此它是四舍五入的。调用库来获得余弦或对数?确切的结果通常是不合理的,所以它是圆的。大多数数学库也有一些额外的错误,因为非常精确地计算这些函数很难。

所以,假设您计算了一些值并在x中得到了结果。它包含了各种错误。然后你计算另一个值并在y得到一个结果。假设,如果用精确数学计算,这两个值将是相等的。 xy中的错误完全相同的几率是多少?

不太可能。如果xy以不同的方式计算,则会遇到不同的错误,并且它们是否具有相同的总错误基本上是偶然的。因此,即使精确的数学结果相等,x == y也可能因错误而错误。

同样,两个确切的数学值可能不同,但错误可能重合,以便x == y返回true。

因此,x == yx != y通常无法用于判断所需的精确数学值是否相等。

可以使用什么?不幸的是,没有一般解决方案。您的示例使用FLT_EPSILON作为错误阈值,但这没有用。在执行了多个浮点运算之后,错误可能很容易累积到FLT_EPSILON以上,无论是绝对错误还是相对错误。

为了进行比较,您需要了解累积误差可能有多大,这在很大程度上取决于您执行的特定计算。你还需要知道误报和漏报的后果是什么 - 更重要的是避免错误地陈述两件事是平等的,或者避免错误地陈述两件事是不平等的?这些问题特定于每种算法及其数据。

答案 1 :(得分:1)

因为在64位机器上你会发现0.1*3 = 0.30000000000000004: - )

请参阅@yano和@ PM-77-1作为评论提供的链接。

答案 2 :(得分:-2)

你知道机器使用0和1存储所有内容。 还要知道并非每个浮点值都可以在有限位内以二进制表示。 计算机存储可能最接近的给定数字的二进制值。

所以他们在计算机眼中是2.0000001和2.0000000之间的区别(但我们说他们是平等的!)。

并不总是出现这种麻烦,但风险很大。