如果比例不是零,则带有百分比的计算(例如 3%2 和 46%4)往往会输出 0。对于非 0 比例,算法是如何设计的?
bc
scale=10
print 4%3 // output 0
答案1
这命令手册关于 BC 如何计算模数,如下所述:
表达式的结果为“余数”,计算方式如下。要计算 a%b,首先一个/b计算成比例数字。该结果用于计算a-(a/b)*b到 scale+scale(b) 和 scale(a) 中最大值的比例。如果比例设置为零并且两个表达式都是整数,则该表达式就是整数余数函数。
编辑: 我查看了 GNU BC 的源代码,发现 mod 运算符扩展了除法运算符。换句话说,模数是作为除法的副产品计算的。它依赖于整数除法来计算模数。
scale
但是,当设置时,不会发生整数除法。
在 BC 尝试一下:
bc
scale = 0
print 5/2
scale = 5
print 5/2
你应该得到:
2 << Integer Division
2.50000 << NOT integer division!
现在让我们按照 BC 的方式代入这些数字。手册上说它使用a-(a/b)*b进行计算。让我们代入两个结果,一个是整数除法的结果,另一个是scale
除以 0 以外的结果。
a - ( a/b ) * b
5 - ( 2 ) * 2 = 1 << CORRECT!
5 - ( 2.5 ) * 2 = 0 << VERY WRONG!
不进行整数除法:
a - ( a/b ) * b == a - ( a ) == 0
这就是为什么必须将比例设置为 0 才能使模数正常工作的原因。
问题似乎源于 BC 的设计以及它如何处理带有“比例”的数字。为了使模数正常工作我们需要整数除法。
答案2
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 ); }
这(使用auto oldscale
)使 成为oldscale
函数的本地变量。如果没有它,则fmod() 中oldscale
的设置将覆盖试图保存在 中的,从而使其设置为 1000,而不是调用 之前的任何值。int()
oldscale
fmod()
scale
fmod()
我将这些函数添加到~/.bcrc
并将BC_ENV_ARGS
环境变量设置为~/.bcrc
。每次运行 bc 时都会加载这些函数。所以现在我可以fmod(x,y)
在 bc 中随时运行,而不必每次都手动定义这些函数。
scale
在大多数情况下,1000 ps可能有点过头了
答案3
我用这种方法解决了:
整数
定义 int(x) { oldscale=scale; scale=0; x=x/1; scale=oldscale; 返回(x); }
模数
定义 mod(x,y) { oldscale=scale; scale=1000; x = x - y * int(x/y); scale=oldscale; 返回(x); }
高血压
答案4
正如其他答案所说,它是定义a%b
为的结果(a-(a/b)*b)
,在当前 处进行评估scale
。这意味着如果您希望它充当整数模数,则需要将其与 一起使用scale=0
。
然而,我不同意它是“错误的”。它是一种潜在的有用工具,特别是用于评估错误。
scale=5
1/3
> .33333
1%3
> .00001
7/13
如果我们将其表示为 4 位小数,我们会失去什么.5384
?
scale=4
7/13
> .5384
7%13
> .0008
显然0.0008/13
。
最后,因为它不坚持使用整数,所以它可以用于提取小数的一部分。
scale=1
123.456/1
> 123.4
123.456%1
> .056