c++ - 在处理浮点值时,我应该结合乘法和除法步骤吗?

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

我知道浮点数和 double 数的精度问题,这就是我问这个的原因:

如果我有一个公式,例如:(a/PI)*180.0 (其中 PI 是常数)

我应该把除法和乘法结合起来,所以我只能用一个除法:a/0.017453292519943295769236 ,为了避免精度损失?

当计算结果的步骤较少时,这是否使它更精确?

最佳答案

简答

是的,您通常应该将尽可能多的乘法和除法组合成一个运算。它(通常(*))同时更快,更准确。

π 和 π/180 以及它们的倒数都不能精确地表示为浮点数。为此,计算将涉及至少一个近似常数(除了所涉及的每个操作的近似值)。

因为两个操作各自引入一个近似值,所以可以预期在一个操作中完成整个计算会更准确。

在手头的情况下,除法还是乘法更好?

除此之外,以浮点格式表示 π/180 的相对精度是比 180/π 好还是差是“运气”的问题。

我的编译器通过 long double 提供加法精度类型,所以我可以用它作为引用来回答 double 的这个问题:

~ $ cat t.c
#define PIL 3.141592653589793238462643383279502884197L

#include <stdio.h>

int main() {

  long double heop = 180.L / PIL;
  long double pohe = PIL / 180.L;
  printf("relative acc. of π/180: %Le\n", (pohe - (double) pohe) / pohe);
  printf("relative acc. of 180/π: %Le\n", (heop - (double) heop) / heop);
}
~ $ gcc t.c && ./a.out 
relative acc. of π/180: 1.688893e-17
relative acc. of 180/π: -3.469703e-17

在通常的编程实践中,人们不会打扰并简单地乘以(浮点表示)180/π,因为乘法比除法快得多。
事实证明,在 binary64 浮点类型的情况下 double几乎总是映射到,π/180 可以用比 180/π 更好的相对精度表示,所以 π/180 是应该用来优化精度的常数:a / ((double) (π / 180)) .使用此公式,总相对误差将近似为常数 (1.688893e-17) 的相对误差与除法的相对误差之和(取决于 a 的值,但永远不会超过2-53)。

更快、更准确结果的替代方法

请注意,除法非常昂贵,您可以通过使用一次乘法和一次 fma 更快地获得更准确的结果: let heop1做最好的double 180/π 的近似值,以及 heop2最好的double 180/π 的近似值 - heop1 .那么结果的最佳值可以计算为:
double r = fma(a, heop1, a * heop2);

以上是绝对最好的事实double对真实计算的逼近是一个定理(实际上是一个有异常(exception)的定理。详细内容可以在《浮点运算手册》中找到)。但即使你想乘以一个 double 的实常数通过以获取 double结果是定理的异常(exception)之一,上面的计算显然仍然非常准确,只是与最好的double不同。 a 的几个异常值的近似值.

如果像我一样,您的编译器为 long double 提供了更高的精度比 double ,您也可以使用一个 long double乘法:
// this is more accurate than double division:
double r = (double)((long double) a * 57.295779513082320876798L)

这不如基于 fma 的解决方案好,但对于 a 的大多数值来说已经足够了。 ,它产生最优 double对实际计算的近似。

操作应归为一个的一般主张的反例

(*) 最好将常数分组的说法仅在统计上对大多数常数是正确的。

如果您碰巧想乘以a例如,实常数 0.0000001 * DBL_MIN ,你最好先乘以 0.0000001 ,然后通过 DBL_MIN ,并且最终结果(如果 a 大于 1000000 左右,则可以是归一化数字)将比乘以最好的 double 更精确。 0.0000001 * DBL_MIN 的表示.这是因为表示 0.0000001 * DBL_MIN 时的相对精度作为单例double值比表示 0.0000001 的准确度差得多。

关于c++ - 在处理浮点值时,我应该结合乘法和除法步骤吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26655948/

相关文章:

c++ - 在构造函数中声明 2D vector

c++ - 将自定义对象附加到 Qt 中的 QStandardItem

c++ - 是否有语法来防止类的实例是常量?

从函数返回 vector 时 C++ 中止(核心转储)

winapi - CDialog - 来自无模式对话框的 EndDialog?

c++ - 在C++中声明一个较大的全局变量会导致错误消息0xc0000018

c++ - Qt Creator 程序因使用 taglib 而崩溃

java Float.MAX_VALUE 转 Double

c - 如何使用DBL_MANT_DIG检查strtod

math - float 学有问题吗?