这是一个自我回答问题,提出问题的合理研究放在答案部分,请不要投反对票,因为您认为我没有对答案进行足够的研究。谢谢。无论如何,在这个网站上没有(我能找到的)关于 bc 这个特性的描述。
当使用 时bc
,该%
运算符被声称要计算“余数”,是的,它适用于整数,并且当规模为零:
$ bc <<<' scale=0; 27 % 7 '
6
但如果小数位数不为零,则无法给出“整数余数”:
$ bc <<<' scale=10; 27 % 7 '
.0000000003
为什么(或者如何)这个模的定义%
有用?
答案1
运营%
商说得很清楚bc
手册中定义的作为[A]:
# Internal % operator definition:
define internalmod(n,d,s) { auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r) }
假设max
已定义为:
define max(x,y){ if(x>y){return(x)};return(y) }
这么长的定义有什么用呢?
整数余数。
我将展示internalmod
函数和%
运算符结果,以证明它们对于接下来的某些操作是等效的。如果数字是整数,并且scale设置为0,则它是整数余数函数。
$ bc <<<'n=17; d=3; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"\n"' 2 2 $ bc <<<'n=17; d=6; scale=0;a=internalmod(n,d,scale);b=n%d;print a," ",b,"\n"' 5 5
这与数学 mod 函数不同。我将在下面解决这个问题。
小数余数。
如果数字n
是更长的十进制数字,并且我们修改比例,我们会得到:$ bc <<<'n=17.123456789;d=1; scale=0 ;a=internalmod(n,d,scale);b=n%d; print a," ",b,"\n"' .123456789 .123456789 $ bc <<<'n=17.123456789;d=1; scale=3 ;a=internalmod(n,d,scale);b=n%d; print a," ",b,"\n"' .000456789 .000456789
请注意,此处删除了前 3 位小数,剩下的部分来自第四个小数。
$ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d; print a," ",b,"\n"' .000000089 .000000089
这表明,根据该定义,其余部分变得更加通用。
现在是:余数后规模的价值。
规模变化 需要更改小数位数,因为数字
d
(除数)的小数位数可能多于n
。在这种情况下,需要更多的小数才能得到更精确的除法结果:$ bc <<<'n=17.123456789; d=1.00000000001; scale=0; a=internalmod(n,d,scale); b=n%d; print a," ",scale(a)," -- ", b," ",scale(b),"\n"' .12345678883 11 -- .12345678883 11
并且,如果比例发生变化:
$ bc <<<'n=17.123456789; d=1.00000000001; scale=5; a=internalmod(n,d,scale); b=n%d; print a," ",scale(a)," -- ", b," ",scale(b),"\n"' .0000067888287655 16 -- .0000067888287655 16
n
从上面可以看出,对于、d
和的任何值,比例值都会发生变化,以呈现相当精确的除法结果scale
。
我假设通过internalmod
和%
运算符之间的比较,两者已被证明是等效的。
困惑。请小心,因为使用 的值
d
可能会变得令人困惑:$ bc <<<'n=17.123456789; d=10; scale=3; a=n%d; print a," ",scale(a),"\n"' .003456789 9
和:
$ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d; print a," ",scale(a),"\n"' .123456789 9
即:(
d
以上1)的值会修改比例集值的效果。
d
也许,对于不同于 1 的值,您应该使用scale=0(除非您真的知道自己在做什么)。
数学模型。
由于我们正在深入研究 mod 函数,因此我们可能应该澄清%
in的真正效果bc
。 bc 中的运算%
符使用“截断除法”。一个四舍五入的方向0
。这对于n
和/或 的负值很重要d
:$ bc <<<'scale=0; n=13; d=7; n%d; ' 6 $ bc <<<'scale=0; n=13; d=-7; n%d; ' 6
余数的符号跟在 的符号后面
dividend
。$ bc <<<'scale=0; n=-13; d=7; n%d; ' -6 $ bc <<<'scale=0; n=-13; d=-7; n%d; ' -6
虽然一个正确的数学模组应该给余数始终为正。
要获得该(整数)mod 函数,请使用:
# Module with an always positive remainder (euclid division). define modeuclid(x,div) { if(div!=int(div)){ "error: divisor should be an integer ";return(0)}; return(x - div*int(x/div)) }
然后(然后)这将起作用:
$ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)" 6.123456789
[A]
expr % expr
表达式的结果是“余数”,其计算方式如下。为了计算 a%b,首先计算 a/b 以缩放数字。该结果用于将 a-(a/b)*b 计算为scale+scale(b) 和scale(a) 中最大值的比例。
如果小数位数设置为零并且两个表达式都是整数,则该表达式是整数余数函数。
为了使bc
引入此脚注的点后面的代码能够正常工作,请将别名定义为:
$ alias bc='bc -l "$HOME/.func.bc"'
并创建一个名为$HOME/.func.bc
包含(至少)的文件:
# Internal % operator definition:
define internalmod(n,d,s) { auto r,oldscale;
oldscale=scale; r=n/d;
s=max(s+scale(d),scale(n));
scale=s; r = n-(r)*d;
scale=oldscale; return(r) }
# Max function
define max(x,y){ if(x>y){return(x)};return(y) }
# Integer part of a number toward 0: -1.99 -> -1, 0.99 -> 0
define int(x) { auto os;os=scale;scale=0;
x=sgn(x)*abs(x)/1;scale=os;return(x) }
define sgn (x) { if (x<0){x=-1};if(x>0){x=1};return(x) };
define abs (x) { if (x<0) x=-x; return x };
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) { if(div!=int(div)){
"error: divisor should be an integer ";return(0)};
return(x - div*int(x/div)) }
任何数字(整数或非整数)的 mod 函数可以定义为:
# Module with an always positive remainder (euclid division).
define modeuclid(x,div) { div=abs(div);return(x - div*floor(x/div)) }
# Round down to integer below x (toward -inf).
define floor (x) { auto os,y;os=scale;scale=0;
y=x/1;if(y>x){y-=1};scale=os;return(y) };
根据数学规则,这个定义是完全有效和正确的,但是,当尝试将其应用于实际情况时,它可能会变得相当混乱,只是说。
答案2
BC 及其运算符的描述是 POSIX 标准的一部分。目前,它就在这里:
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html
a % b 定义为 a - (a / b) * b 并计算为 max(scale + scale(b), scale(a))。
从当前版本 1.07.1 开始,GNU BC 就是这种情况。对于BSD来说,BC只是DC的一个外壳,DC使用“bn”代表“%”。
在C-BC中也是如此。 C-BC,其来源存档在这里:
https://github.com/RockBrentwood/CBC
是 BC 的大型扩展,更接近 C,并且(大部分)是 GNU BC 和 BSD BC 的超集。