【问题标题】:Manual Math.pow() losing precision using float手动 Math.pow() 使用浮点数丢失精度
【发布时间】:2013-08-20 12:20:37
【问题描述】:

我正在尝试在 C 中进行手动操作(相当于 Math.pow()),所以在这里,它是:41619^6

  float sum = 41619;
  float a = sum;
  int k;
  for (k = 0; k < 5; k++) {
    sum = sum * a;
  }
  printf("%f", sum);
  // sum should be 41619 ^ 6 now

但是,我在这里失去了精确度。我收到5196966085285475633789403136,答案应该是5196965646007524312007756281

我尝试将 sum 更改为 double,但仍然丢失精度。

如何在不使用 Math.pow() 的情况下实现这一点(对于我尝试运行的测试来说太慢了),并且不损失精度?

【问题讨论】:

  • 您是否考虑过原因 pow 速度慢的可能性是它不会丢失精度?
  • 话虽如此,没有办法将确切的值存储在float 甚至double 中。这些类型根本没有足够的精度来表示它。但是,pow 比您的循环做得更好。
  • log_2 5196965646007524312007756281 ≈ 92。这个数量级的大多数整数不能用单精度或双精度浮点数(23 或 52 位尾数)精确表示。也许这个特定的数字恰好是可以概括表示的那些数字之一,但这也不足为奇。
  • @delnan:不,它不是其中之一。对于 2^n, 2^(n+1) 范围内的任何奇数 x,x^k 是奇数(因此仍然需要最低位),并且最高位在 n*k 或更高的位置。除非 n 和 k 都非常小,否则 x^k 不能精确表示。
  • 顺便说一句,稍微提高精度和速度的一种方法是将操作重组为(a*a)*(a*a)*(a*a)。这只需要 3 次乘法而不是 5 次。

标签: c math double precision


【解决方案1】:

看来你想做computations on Big Integers。 Big Integer 是一个整数,其值大于2^64。计算机体系结构本身并不支持大整数,因为它们需要比 CPU 中的寄存器更多的位。在每种计算机语言中都有很多方法可以使用大整数。对于C,您必须使用库。

我推荐GNU Multiple Precision (GMP) 库。它通常与大多数C 编译器一起预安装,只需要#include &lt;gmp.h&gt; 和编译器标志-lgmp

阅读GMP manual 了解支持的功能的大量列表。

与您或我在此应用程序领域中所拥有的相比,许多、许多、许多具有更明确优化重点的协作思想使 GMP 库在不损失精度的情况下尽可能高效。

应该注意pow() 通常在协处理器中使用硬件查找表,并且仅限于浮点数。对于以浮点形式表示的非常大的数字,这可能会导致明显的不精确性。 Big Integer 库将使用各种数学技术,在不损失精度的情况下最大限度地提高计算效率,例如exponentiation by squaring

当标准轮子失效时,不要重新发明轮子,只需寻找一个不同的、更专业的轮子。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-07
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多