Math OpenEdge abl truncate(日志(4)/日志(2))应为2返回1

Math OpenEdge abl truncate(日志(4)/日志(2))应为2返回1,math,floating-point,progress-4gl,openedge,Math,Floating Point,Progress 4gl,Openedge,我猜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 a

我猜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)
找到最大的x,其中
p^x
x=对数(n)/对数(p)

有没有这种方法?

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

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

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

但是,对于这个问题,您还需要将
log(8)
精确地设置为
log(2)
的三倍,以此类推以获得额外的功率。即使
log
实现返回了正确的四舍五入结果,对于您需要的所有值,这也不一定都是正确的。对于某些y=x5,
log(y)
可能不正好是
log(x)
的五倍,因为将log(y)舍入到最接近的可表示值可能会向下舍入,而将log(x)舍入到最接近的可表示值,这仅仅是因为精确值恰好位于最接近的可表示值的相对位置

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

我认为您需要:

/* 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
.
/*找到最大的x,其中p^x,>>>,>>>,>>9”。
将变量x定义为整数无撤消格式“>>9”。
将变量n定义为整数无撤消格式“>,>>>,>>>,>>9”。
将变量i定义为整数无撤消格式“->>9”。
将变量z定义为十进制无撤消格式“>>9.9999999”。
用侧面标签更新PN。
/*近似x
*/
z=对数(n)/对数(p)。
显示z。
x=整数(截断(z,0))。/*估计数x*/
/*p^x=n,那么
当exp(p,x)>=n://*时,估计值是否过高*/
分配
i=i-1
x=x-1
.
结束。
其他的
当exp(p,x+1),>>>,>>>,>>9”跳过
我跳过
日志(n)跳过
日志(p)跳过
z跳跃
具有
侧标签
.

问题的根源在于易受浮点截断错误影响的log函数正被用于解决自然数领域的一个问题。首先,我应该指出,实际上,在给出的例子中,1确实是正确的答案。我们正在寻找最大的x,使得p^x 解决方法:避免截断使用圆形

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

四舍五入(a,b)将小数点a四舍五入到最接近的有b位小数的数字。

我对此有点困惑。如果一个正确舍入的
log
和一个
x
,其中
x*x
是可精确表示的,并且没有发生溢出或下溢的恶作剧,那么肯定
log(x*x)==2*log(x)
?@tmyklebu:是的,对于二进制浮点来说是这样的。然而,对于这个问题,我们还需要
log(x*x*x)==3*log(x)
,而这不适用于二进制浮点。我将更新答案。这会在结果接近整数解时产生错误,这将给您一个假阳性。这不会引发错误。它对误报不比提供的任何其他解决方案更敏感。如果在位置0处舍入值,则会得到错误的值,例如log(9)/log(8)=>1,而不是定义要求的0。当我说错误时,我指的是数学上的错误,很抱歉没有具体说明;-)显示日志(8)格式“9.9999999999”日志(9)格式“9.9999999999”截断(圆形(日志(9)/日志(8),0),0)。2.0794415417 2.1972245773 1.00@Mark:也许你应该重读你自己的答案?你说“没有其他更好的选择,比如不同的舍入函数……”,那么还有另一个舍入函数。它被称为ROUND()。
display  truncate(log(4) / log(2)  - 0.00000001, 0) .
display  truncate(log(4) / log(2) , 0) .
 ROUND(log(4) / log(2), 0).