这么长的定义有什么用呢?

这么长的定义有什么用呢?

这是一个自我回答问题,提出问题的合理研究放在答案部分,请不要投反对票,因为您认为我没有对答案进行足够的研究。谢谢。无论如何,在这个网站上没有(我能找到的)关于 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) }

这么长的定义有什么用呢?

  1. 整数余数
    我将展示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 函数不同。我将在下面解决这个问题。

  1. 小数余数。
    如果数字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
    

    这表明,根据该定义,其余部分变得更加通用。

现在是:余数规模的价值。

  1. 规模变化 需要更改小数位数,因为数字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%运算符之间的比较,两者已被证明是等效的。

  1. 困惑。请小心,因为使用 的值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(除非您真的知道自己在做什么)。

  1. 数学模型
    由于我们正在深入研究 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 的超集。

相关内容