GNU BC:“模”% 的比例不是 0

13 bc

如果尺度不是零,用%计算,比如3%2和46%4,往往会输出0。非0尺度的算法是如何设计的?

bc
scale=10
print 4%3   // output 0
Run Code Online (Sandbox Code Playgroud)

jwe*_*ede 14

命令手册说,这大约在公元前如何计算模:

表达式的结果是“余数”,其计算方式如下。要计算 a%b,首先计算a/b以缩放数字。该结果用于将a - ( a/b ) * b计算为 scale+scale(b) 和 scale(a) 的最大值。如果 scale 设置为零并且两个表达式都是整数,则此表达式是整数余数函数。


编辑: 我查看了 GNU BC 的源代码,发现 mod 运算符扩展了除法运算符。换句话说,模数被计算为除法的副产品。它依靠整数除法来计算模数。当scale设置,但整数除法不会发生。

在 BC 试试这个:

bc
scale = 0
print 5/2

scale = 5
print 5/2
Run Code Online (Sandbox Code Playgroud)

你应该得到:

2        << Integer Division
2.50000  << NOT integer division!
Run Code Online (Sandbox Code Playgroud)

现在让我们按照 BC 的方式插入这些数字。手册说它使用a-(a/b)*b来计算。让我们插入我们的两个结果,一个是整数除法的结果,scale另一个是除 0 以外的结果。

a - ( a/b ) * b
5 - ( 2   ) * 2  = 1  << CORRECT!
5 - ( 2.5 ) * 2  = 0  << VERY WRONG!
Run Code Online (Sandbox Code Playgroud)

没有整数除法:

a - ( a/b ) * b == a - (  a  ) == 0
Run Code Online (Sandbox Code Playgroud)

这就是为什么 scale 必须设置为 0 才能使模正常工作。
这个问题似乎源于 BC 的设计以及它如何处理带有“比例”的数字。为了使模正常工作,我们需要整数除法

还有其他很多更高级的工具是用于此目的的自由和开放源码,我建议你使用它们。

  • 当它说不带括号的“scale”时,它指的是全局变量“scale”。 (2认同)

小智 5

user272970的回答很好。这是对其的一个调整:

define int(x) { auto oldscale; oldscale=scale; scale=0; x=x/1; scale=oldscale; return( x ); }
define fmod(x,y) { auto oldscale; oldscale=scale; scale=1000; x = x - y * int(x/y); scale=oldscale; return( x ); }
Run Code Online (Sandbox Code Playgroud)

这(使用auto oldscale)使oldscale函数成为本地函数。如果没有这个,从 fmod()oldscale中进行的设置将覆盖尝试保存在 中的,将设置保留为 1000 而不是调用之前的任何内容。int()oldscalefmod()scalefmod()

我将这些函数添加到~/.bcrc并将BC_ENV_ARGS环境变量设置为~/.bcrc. 每次运行 bc 时都会加载这些函数。所以现在我可以在 bc 中随时运行,fmod(x,y)而不必每次都手动定义这些函数。

在大多数情况下,1000 的psscale可能有点过大