c++ - 浮点运算

标签 c++ c floating-point precision floating-point-conversion

今天在我的 C++ 编程课上,我的教授告诉我,永远不要直接比较两个浮点值。

于是我尝试了这段代码,找出了他这种说法的原因。

double l_Value=94.9;
print("%.20lf",l_Value);

我发现结果为 94.89999999(一些相对错误)

我知道 float 不是以呈现给代码的方式存储的。以二进制形式压缩这些 1 和 0 涉及一些相对舍入误差。

我正在寻找两个问题的解决方案。 1. 比较两个浮点值的有效方法。 2.如何将一个 float 值添加到另一个。例子。将 0.1111 添加到 94.4345 得到精确值 94.5456

提前致谢。

最佳答案

  1. Efficient way to compare two floating values.

一个简单的 double a,b; if (a == b) 是比较两个浮点值的有效方法。然而,正如 OP 所注意到的,这可能不符合总体编码目标。更好的方法取决于比较的上下文,OP 没有提供。请看下面。

  1. How to add a floating value to another one. Example. Add 0.1111 to 94.4345 to get the exact value as 94.5456

作为源代码的浮点值具有有效的无限范围和精度,例如1.23456789012345678901234567890e1234567。将此文本转换为 double 通常限于 264 个不同值之一。选择最接近的,但可能不完全匹配。

0.1111、94.4345、94.5456 都不能完全表示为典型的 double

OP 有选择:

1.) 使用不同于double, float 的其他类型。各种库提供十进制浮点类型。

2) 将支持 double 的罕见平台的代码限制为以 10 为底的形式,例如 FLT_RADIX == 10

3) 编写您自己的代码来处理用户输入,如 "0.1111" 到结构/字符串中并执行所需的操作。

4) 将用户输入视为字符串并转换为某种整数类型,再次使用支持的例程来读取/计算/写入。

5) 接受浮点运算在数学上并不精确并处理舍入误差。

double a = 0.1111;
printf("a:   %.*e\n", DBL_DECIMAL_DIG -1 , a);
double b = 94.4345;
printf("b:   %.*e\n", DBL_DECIMAL_DIG -1 , b);
double sum = a + b;
printf("sum: %.*e\n", DBL_DECIMAL_DIG -1 , sum);
printf("%.4f\n", sum);

输出

a:   1.1110000000000000e-01
b:   9.4434500000000000e+01
sum: 9.4545599999999993e+01
94.5456  // Desired textual output based on a rounded `sum` to the nearest 0.0001

More on #1

如果不寻求精确比较,而是寻求某种“这两个值是否足够接近?”,则需要“足够接近”的定义 - 有很多这样的定义。

下面的“足够接近”通过检查两个数的ULP来比较距离。当值是相同的二次方时,它是线性差异,否则变为对数。当然,更改符号是一个问题。

float 示例:
考虑从最负到最正排序的所有有限float。下面的可移植代码以相同的顺序为每个float 返回一个整数。

uint32_t sequence_f(float x) {
  union {
    float f;
    uint32_t u32;
  } u;
  assert(sizeof(float) == sizeof(uint32_t));
  u.f = x;
  if (u.u32 & 0x80000000) {
    u.u32 ^= 0x80000000;
    return 0x80000000 - u.u32;
  }
  return u.u3
}

现在,要确定两个 float 是否“足够接近”,只需比较两个整数。

static bool close_enough(float x, float y, uint32_t ULP_delta) {
  uint32_t ullx = sequence_f(x);
  uint32_t ully = sequence_f(y);
  if (ullx > ully) return (ullx - ully) <= ULP_delta;
  return (ully - ullx) <= ULP_delta;
}

关于c++ - 浮点运算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43327915/

相关文章:

c++ - 创建 OpenGL 2D View 相机,但使用模型 View 投影相机

c++ - 从具有相同基类的另一个派生类调用派生类的非常量方法

java - 如何访问另一个程序中已经构建的链表?

c - 如何定义大于 16 字节的 float 据类型?

javascript - 为什么 (-2.4492935982947064e-16).toFixed(5) 等于 "-0.00000"?

C:从 String 到 Double 的转换给出了奇怪的结果

c++ - Windows 2012 R2 closesocket() 卡在监听套接字上

c++ - 避免为单个 header 重新定义变量

c - fork 和管道 : does this C program contain a race condition?

c - C 中的严格别名