2

我有一个问题,我猜是 OpenEdge ABL / Progress 4GL 中的浮点舍入错误

display  truncate(log(4) / log(2) , 0) .

这返回 1.0 但应该给我一个 2.0

如果我做这个伪解决方案,它在大多数情况下都会给我正确的答案,提示浮点数。

display  truncate(log(4) / log(2)  + 0.00000001, 0) .

我追求的是这个

find the largest x where 

p^x < n, p is prime, n and x is natural numbers.

=>

x = log(n) / log(p)

有这个的吗?

4

4 回答 4

2

没有数字算术系统是精确的。4 和 2 的自然对数不能精确表示。由于该log函数只能返回一个可表示的值,因此它返回精确数学结果的近似值。

有时这个近似值会略高于数学结果。有时会稍微低一些。因此,您通常不能期望log(x*x)恰好是两倍log(x)

理想情况下,高质量的log实现将返回最接近精确数学值的可表示值。(这被称为“正确舍入”的结果。)在这种情况下,如果您使用二进制浮点(这很常见),那么log(4)总是恰好是 two log(2)。由于您不会发生这种情况,因此log您使用的实现似乎没有提供正确的舍入结果。

但是,对于这个问题,您还需要log(8)精确 3 次log(2),以此类推以获得额外的权力。即使log实现确实返回了正确的舍入结果,对于您需要的所有值来说,这也不一定是正确的。对于某些 y = x 5log(y)可能不完全是五倍log(x),因为将 log(y) 舍入到最接近的可表示值可能会向下舍入,而将 log(x) 舍入可能会向上舍入,这只是因为精确值恰好相对于最接近的可表示值。

因此,即使是最好的实现,您也无法准确地告诉您除某个数字log有多少次幂。您可以接近,然后您可以通过整数运算确认或否认结果来测试结果。根据您具体情况的需要,可能还有其他方法。xy

于 2013-10-02T14:48:08.983 回答
0

大多数计算器也无法计算 sqrt{2}*sqrt{2}。问题是我们通常没有那么多小数。

解决方法:避免 TRUNCATE 使用 ROUND like

 ROUND(log(4) / log(2), 0).

Round(a,b) 将小数 a 向上舍入到具有 b 小数的最接近的数字。

于 2013-10-11T14:13:05.033 回答
0

问题的根源在于,易受浮点截断错误影响的 log 函数被用于解决自然数领域的问题。首先,我应该指出,实际上,在给出的示例中,1 确实是正确答案。我们正在寻找最大的 x 使得 p^x < n; 不是 p^x <= n。2^1 < 4,但 2^2 不是。话虽如此,我们仍然有一个问题,因为当 p^x = n 对于某些 x 时,log(n) 除以 log(p) 可能会略高于整数而不是低于整数,除非有一些系统性在实现日志功能时存在偏差。所以在这种情况下,有一些 x 为 p^x=n,我们实际上希望确保向下舍入到下一个较低的 x 整数值。

所以即使是这样的解决方案也不能解决这个问题:

display  truncate(round(log(4) / log(2), 10) , 0) .

我看到两种方法来处理这个问题。一个类似于您已经尝试过的,除了因为我们实际上想要向下舍入到下一个较低的自然数,我们将减去而不是添加:

display  truncate(log(4) / log(2)  - 0.00000001, 0) .

只要 n 小于 10^16,这将起作用,但更简洁的解决方案是使用实际整数数学来解决边界条件。当然,如果你得到的数字高于最大整数值,这也会失败。但如果这不是问题,您可以使用您的第一个解决方案获得近似解决方案:

display  truncate(log(4) / log(2) , 0) .

然后测试结果是否适用于方程 p^x < n。如果不小于 n,则减一并重试。

顺便说一句,自然数的定义不包括零,所以如果 x 的最低可能值为 1,那么 p^x 的最低可能值为 p,所以如果 n 小于或等于到 p,没有自然数解。

于 2013-10-07T21:17:44.470 回答
0

我想你想要:

/* find the largest x where p^x < n, p is prime, n and x is natural numbers.
 */

define variable p as integer no-undo format ">,>>>,>>>,>>9".
define variable x as integer no-undo format ">>9".
define variable n as integer no-undo format ">,>>>,>>>,>>9".

define variable i as integer no-undo format "->>9".

define variable z as decimal no-undo format ">>9.9999999999".

update p n with side-labels.

/* approximate x
 */

z = log( n ) / log( p ).
display z.

x = integer( truncate( z, 0 )).  /* estimate x                */

/* is p^x < n ?
 */

if exp( p, x ) >= n then
  do while exp( p, x ) >= n:    /* was the estimate too high? */
    assign
      i = i - 1
      x = x - 1
    .
  end.
 else
  do while exp( p, x + 1 ) < n:  /* was the estimate too low? */
    assign
      i = i + 1
      x = x + 1
    .
  end.

display
  x skip
  exp( p, x ) label "p^x" format ">,>>>,>>>,>>9" skip
  i skip
  log( n ) skip
  log( p ) skip
  z skip
 with
  side-labels
.
于 2013-10-02T20:33:39.800 回答