GNU BC: How is the “modulo” (%) with scale other than 0 useful?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
0
down vote

favorite












This is a self-answered question, the research that is reasonable to ask for a question goes in the answer part, Please do not downvote because you believe I have not researched enough for an answer. Thanks. In any case, there is no description (that I can find) of this characteristic of bc in this site.



When using bc, the % operator is claimed to calculate the "remainder", and yes, it works for integer numbers and when the scale is zero:



$ bc <<<' scale=0; 27 % 7 '
6


But it fails to give the "integer remainder" if the scale is not zero:



$ bc <<<' scale=10; 27 % 7 '
.0000000003


Why (or how) is this definition of the % modulo useful?









share

























    up vote
    0
    down vote

    favorite












    This is a self-answered question, the research that is reasonable to ask for a question goes in the answer part, Please do not downvote because you believe I have not researched enough for an answer. Thanks. In any case, there is no description (that I can find) of this characteristic of bc in this site.



    When using bc, the % operator is claimed to calculate the "remainder", and yes, it works for integer numbers and when the scale is zero:



    $ bc <<<' scale=0; 27 % 7 '
    6


    But it fails to give the "integer remainder" if the scale is not zero:



    $ bc <<<' scale=10; 27 % 7 '
    .0000000003


    Why (or how) is this definition of the % modulo useful?









    share























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      This is a self-answered question, the research that is reasonable to ask for a question goes in the answer part, Please do not downvote because you believe I have not researched enough for an answer. Thanks. In any case, there is no description (that I can find) of this characteristic of bc in this site.



      When using bc, the % operator is claimed to calculate the "remainder", and yes, it works for integer numbers and when the scale is zero:



      $ bc <<<' scale=0; 27 % 7 '
      6


      But it fails to give the "integer remainder" if the scale is not zero:



      $ bc <<<' scale=10; 27 % 7 '
      .0000000003


      Why (or how) is this definition of the % modulo useful?









      share













      This is a self-answered question, the research that is reasonable to ask for a question goes in the answer part, Please do not downvote because you believe I have not researched enough for an answer. Thanks. In any case, there is no description (that I can find) of this characteristic of bc in this site.



      When using bc, the % operator is claimed to calculate the "remainder", and yes, it works for integer numbers and when the scale is zero:



      $ bc <<<' scale=0; 27 % 7 '
      6


      But it fails to give the "integer remainder" if the scale is not zero:



      $ bc <<<' scale=10; 27 % 7 '
      .0000000003


      Why (or how) is this definition of the % modulo useful?







      shell bc





      share












      share










      share



      share










      asked 1 min ago









      Isaac

      8,58211241




      8,58211241




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          The % operator is clearly defined in the bc manual as [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)


          Assuming max has been defined as:



          define max(x,y) if(x>y)return(x);return(y) 


          How is that long definition useful?




          1. Integer remainder.

            I'll show both the internalmod function and the % operator results to prove that they are equivalent for some of the next operations.



            If the numbers are integer, and scale is set to 0, it is the integer remainder function.



            $ 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


          That is not the same as the math mod function. I'll solve that below.




          1. Decimal remainder.

            If the number n is a longer decimal number, and we modify the scale, we get:



            $ 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


            Note that here, the first 3 decimal digits were removed and the remainder given is from the fourth decimal digit.



            $ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;
            print a," ",b,"n"'
            .000000089 .000000089


            That shows that the remainder is made more versatile by that definition.



          Now it is: the remainder after the value of scale.




          1. Scale change
            The change of scale is required because the number d (divisor) may have more decimal digits than n. In that case, more decimals are needed to have a more precise result from the division:



            $ 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


            And, if the scale change:



            $ 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


            As can be seen above, the scale value changes to present a reasonably precise result of the division for any value of n, d and scale.



          I'll assume that by the comparison between the internalmod and the % operator both have been proven to be equivalent.




          1. Confusion.
            Be careful because playing with the value of d may become confusing:



            $ bc <<<'n=17.123456789; d=10; scale=3; a=n%d;
            print a," ",scale(a),"n"'
            .003456789 9


            And:



            $ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d;
            print a," ",scale(a),"n"'
            .123456789 9


            That is: the value of d (above 1) will modify the effect of the value of scale set.



          Probably, for values of d different than 1 you should use scale=0 (unless you really know what you are doing).




          1. Math mod.

            Since we are taking such a deep dive into mod functions, we probably should clarify the real effect of % in bc. The % operator in bc is using a "truncating division". One that rounds toward 0. That is important for negative values of both n and/or d:



            $ bc <<<'scale=0; n=13; d=7; n%d; '
            6

            $ bc <<<'scale=0; n=13; d=-7; n%d; '
            6


            The sign of the remainder follows the sign of the dividend.



            $ bc <<<'scale=0; n=-13; d=7; n%d; '
            -6

            $ bc <<<'scale=0; n=-13; d=-7; n%d; '
            -6


            While a correct math mod should give an always positive remainder.



            To get that (integer) mod function, use:



            # 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))


            And (then) this will work:



            $ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
            6.123456789



          [a]




          expr % expr

          The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to scale digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale+scale(b) and scale(a).

          If scale is set to zero and both expressions are integers this expression is the integer remainder function.





          For the bc code that follows the point where this footnote was introduced to work correctly, define an alias as:



          $ alias bc='bc -l "$HOME/.func.bc"'


          And create a file named $HOME/.func.bc that contains (at least):



          # 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))



          A mod function for any number (integer or not) may be defined as:



          # 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) ;


          This definition is perfectly valid and correct by math rules, however, it may become quite confusing when trying to apply it in real cases, just saying.





          share




















            Your Answer







            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "106"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f478192%2fgnu-bc-how-is-the-modulo-with-scale-other-than-0-useful%23new-answer', 'question_page');

            );

            Post as a guest






























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            0
            down vote













            The % operator is clearly defined in the bc manual as [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)


            Assuming max has been defined as:



            define max(x,y) if(x>y)return(x);return(y) 


            How is that long definition useful?




            1. Integer remainder.

              I'll show both the internalmod function and the % operator results to prove that they are equivalent for some of the next operations.



              If the numbers are integer, and scale is set to 0, it is the integer remainder function.



              $ 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


            That is not the same as the math mod function. I'll solve that below.




            1. Decimal remainder.

              If the number n is a longer decimal number, and we modify the scale, we get:



              $ 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


              Note that here, the first 3 decimal digits were removed and the remainder given is from the fourth decimal digit.



              $ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;
              print a," ",b,"n"'
              .000000089 .000000089


              That shows that the remainder is made more versatile by that definition.



            Now it is: the remainder after the value of scale.




            1. Scale change
              The change of scale is required because the number d (divisor) may have more decimal digits than n. In that case, more decimals are needed to have a more precise result from the division:



              $ 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


              And, if the scale change:



              $ 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


              As can be seen above, the scale value changes to present a reasonably precise result of the division for any value of n, d and scale.



            I'll assume that by the comparison between the internalmod and the % operator both have been proven to be equivalent.




            1. Confusion.
              Be careful because playing with the value of d may become confusing:



              $ bc <<<'n=17.123456789; d=10; scale=3; a=n%d;
              print a," ",scale(a),"n"'
              .003456789 9


              And:



              $ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d;
              print a," ",scale(a),"n"'
              .123456789 9


              That is: the value of d (above 1) will modify the effect of the value of scale set.



            Probably, for values of d different than 1 you should use scale=0 (unless you really know what you are doing).




            1. Math mod.

              Since we are taking such a deep dive into mod functions, we probably should clarify the real effect of % in bc. The % operator in bc is using a "truncating division". One that rounds toward 0. That is important for negative values of both n and/or d:



              $ bc <<<'scale=0; n=13; d=7; n%d; '
              6

              $ bc <<<'scale=0; n=13; d=-7; n%d; '
              6


              The sign of the remainder follows the sign of the dividend.



              $ bc <<<'scale=0; n=-13; d=7; n%d; '
              -6

              $ bc <<<'scale=0; n=-13; d=-7; n%d; '
              -6


              While a correct math mod should give an always positive remainder.



              To get that (integer) mod function, use:



              # 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))


              And (then) this will work:



              $ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
              6.123456789



            [a]




            expr % expr

            The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to scale digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale+scale(b) and scale(a).

            If scale is set to zero and both expressions are integers this expression is the integer remainder function.





            For the bc code that follows the point where this footnote was introduced to work correctly, define an alias as:



            $ alias bc='bc -l "$HOME/.func.bc"'


            And create a file named $HOME/.func.bc that contains (at least):



            # 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))



            A mod function for any number (integer or not) may be defined as:



            # 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) ;


            This definition is perfectly valid and correct by math rules, however, it may become quite confusing when trying to apply it in real cases, just saying.





            share
























              up vote
              0
              down vote













              The % operator is clearly defined in the bc manual as [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)


              Assuming max has been defined as:



              define max(x,y) if(x>y)return(x);return(y) 


              How is that long definition useful?




              1. Integer remainder.

                I'll show both the internalmod function and the % operator results to prove that they are equivalent for some of the next operations.



                If the numbers are integer, and scale is set to 0, it is the integer remainder function.



                $ 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


              That is not the same as the math mod function. I'll solve that below.




              1. Decimal remainder.

                If the number n is a longer decimal number, and we modify the scale, we get:



                $ 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


                Note that here, the first 3 decimal digits were removed and the remainder given is from the fourth decimal digit.



                $ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;
                print a," ",b,"n"'
                .000000089 .000000089


                That shows that the remainder is made more versatile by that definition.



              Now it is: the remainder after the value of scale.




              1. Scale change
                The change of scale is required because the number d (divisor) may have more decimal digits than n. In that case, more decimals are needed to have a more precise result from the division:



                $ 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


                And, if the scale change:



                $ 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


                As can be seen above, the scale value changes to present a reasonably precise result of the division for any value of n, d and scale.



              I'll assume that by the comparison between the internalmod and the % operator both have been proven to be equivalent.




              1. Confusion.
                Be careful because playing with the value of d may become confusing:



                $ bc <<<'n=17.123456789; d=10; scale=3; a=n%d;
                print a," ",scale(a),"n"'
                .003456789 9


                And:



                $ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d;
                print a," ",scale(a),"n"'
                .123456789 9


                That is: the value of d (above 1) will modify the effect of the value of scale set.



              Probably, for values of d different than 1 you should use scale=0 (unless you really know what you are doing).




              1. Math mod.

                Since we are taking such a deep dive into mod functions, we probably should clarify the real effect of % in bc. The % operator in bc is using a "truncating division". One that rounds toward 0. That is important for negative values of both n and/or d:



                $ bc <<<'scale=0; n=13; d=7; n%d; '
                6

                $ bc <<<'scale=0; n=13; d=-7; n%d; '
                6


                The sign of the remainder follows the sign of the dividend.



                $ bc <<<'scale=0; n=-13; d=7; n%d; '
                -6

                $ bc <<<'scale=0; n=-13; d=-7; n%d; '
                -6


                While a correct math mod should give an always positive remainder.



                To get that (integer) mod function, use:



                # 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))


                And (then) this will work:



                $ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
                6.123456789



              [a]




              expr % expr

              The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to scale digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale+scale(b) and scale(a).

              If scale is set to zero and both expressions are integers this expression is the integer remainder function.





              For the bc code that follows the point where this footnote was introduced to work correctly, define an alias as:



              $ alias bc='bc -l "$HOME/.func.bc"'


              And create a file named $HOME/.func.bc that contains (at least):



              # 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))



              A mod function for any number (integer or not) may be defined as:



              # 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) ;


              This definition is perfectly valid and correct by math rules, however, it may become quite confusing when trying to apply it in real cases, just saying.





              share






















                up vote
                0
                down vote










                up vote
                0
                down vote









                The % operator is clearly defined in the bc manual as [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)


                Assuming max has been defined as:



                define max(x,y) if(x>y)return(x);return(y) 


                How is that long definition useful?




                1. Integer remainder.

                  I'll show both the internalmod function and the % operator results to prove that they are equivalent for some of the next operations.



                  If the numbers are integer, and scale is set to 0, it is the integer remainder function.



                  $ 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


                That is not the same as the math mod function. I'll solve that below.




                1. Decimal remainder.

                  If the number n is a longer decimal number, and we modify the scale, we get:



                  $ 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


                  Note that here, the first 3 decimal digits were removed and the remainder given is from the fourth decimal digit.



                  $ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;
                  print a," ",b,"n"'
                  .000000089 .000000089


                  That shows that the remainder is made more versatile by that definition.



                Now it is: the remainder after the value of scale.




                1. Scale change
                  The change of scale is required because the number d (divisor) may have more decimal digits than n. In that case, more decimals are needed to have a more precise result from the division:



                  $ 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


                  And, if the scale change:



                  $ 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


                  As can be seen above, the scale value changes to present a reasonably precise result of the division for any value of n, d and scale.



                I'll assume that by the comparison between the internalmod and the % operator both have been proven to be equivalent.




                1. Confusion.
                  Be careful because playing with the value of d may become confusing:



                  $ bc <<<'n=17.123456789; d=10; scale=3; a=n%d;
                  print a," ",scale(a),"n"'
                  .003456789 9


                  And:



                  $ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d;
                  print a," ",scale(a),"n"'
                  .123456789 9


                  That is: the value of d (above 1) will modify the effect of the value of scale set.



                Probably, for values of d different than 1 you should use scale=0 (unless you really know what you are doing).




                1. Math mod.

                  Since we are taking such a deep dive into mod functions, we probably should clarify the real effect of % in bc. The % operator in bc is using a "truncating division". One that rounds toward 0. That is important for negative values of both n and/or d:



                  $ bc <<<'scale=0; n=13; d=7; n%d; '
                  6

                  $ bc <<<'scale=0; n=13; d=-7; n%d; '
                  6


                  The sign of the remainder follows the sign of the dividend.



                  $ bc <<<'scale=0; n=-13; d=7; n%d; '
                  -6

                  $ bc <<<'scale=0; n=-13; d=-7; n%d; '
                  -6


                  While a correct math mod should give an always positive remainder.



                  To get that (integer) mod function, use:



                  # 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))


                  And (then) this will work:



                  $ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
                  6.123456789



                [a]




                expr % expr

                The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to scale digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale+scale(b) and scale(a).

                If scale is set to zero and both expressions are integers this expression is the integer remainder function.





                For the bc code that follows the point where this footnote was introduced to work correctly, define an alias as:



                $ alias bc='bc -l "$HOME/.func.bc"'


                And create a file named $HOME/.func.bc that contains (at least):



                # 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))



                A mod function for any number (integer or not) may be defined as:



                # 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) ;


                This definition is perfectly valid and correct by math rules, however, it may become quite confusing when trying to apply it in real cases, just saying.





                share












                The % operator is clearly defined in the bc manual as [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)


                Assuming max has been defined as:



                define max(x,y) if(x>y)return(x);return(y) 


                How is that long definition useful?




                1. Integer remainder.

                  I'll show both the internalmod function and the % operator results to prove that they are equivalent for some of the next operations.



                  If the numbers are integer, and scale is set to 0, it is the integer remainder function.



                  $ 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


                That is not the same as the math mod function. I'll solve that below.




                1. Decimal remainder.

                  If the number n is a longer decimal number, and we modify the scale, we get:



                  $ 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


                  Note that here, the first 3 decimal digits were removed and the remainder given is from the fourth decimal digit.



                  $ bc <<<'n=17.123456789;d=1; scale=7 ;a=internalmod(n,d,scale);b=n%d;
                  print a," ",b,"n"'
                  .000000089 .000000089


                  That shows that the remainder is made more versatile by that definition.



                Now it is: the remainder after the value of scale.




                1. Scale change
                  The change of scale is required because the number d (divisor) may have more decimal digits than n. In that case, more decimals are needed to have a more precise result from the division:



                  $ 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


                  And, if the scale change:



                  $ 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


                  As can be seen above, the scale value changes to present a reasonably precise result of the division for any value of n, d and scale.



                I'll assume that by the comparison between the internalmod and the % operator both have been proven to be equivalent.




                1. Confusion.
                  Be careful because playing with the value of d may become confusing:



                  $ bc <<<'n=17.123456789; d=10; scale=3; a=n%d;
                  print a," ",scale(a),"n"'
                  .003456789 9


                  And:



                  $ bc <<<'n=17.123456789; d=1000; scale=3; a=n%d;
                  print a," ",scale(a),"n"'
                  .123456789 9


                  That is: the value of d (above 1) will modify the effect of the value of scale set.



                Probably, for values of d different than 1 you should use scale=0 (unless you really know what you are doing).




                1. Math mod.

                  Since we are taking such a deep dive into mod functions, we probably should clarify the real effect of % in bc. The % operator in bc is using a "truncating division". One that rounds toward 0. That is important for negative values of both n and/or d:



                  $ bc <<<'scale=0; n=13; d=7; n%d; '
                  6

                  $ bc <<<'scale=0; n=13; d=-7; n%d; '
                  6


                  The sign of the remainder follows the sign of the dividend.



                  $ bc <<<'scale=0; n=-13; d=7; n%d; '
                  -6

                  $ bc <<<'scale=0; n=-13; d=-7; n%d; '
                  -6


                  While a correct math mod should give an always positive remainder.



                  To get that (integer) mod function, use:



                  # 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))


                  And (then) this will work:



                  $ bc <<<"n=7.123456789; d=5; modeuclid(34.123456789,7)"
                  6.123456789



                [a]




                expr % expr

                The result of the expression is the "remainder" and it is computed in the following way. To compute a%b, first a/b is computed to scale digits. That result is used to compute a-(a/b)*b to the scale of the maximum of scale+scale(b) and scale(a).

                If scale is set to zero and both expressions are integers this expression is the integer remainder function.





                For the bc code that follows the point where this footnote was introduced to work correctly, define an alias as:



                $ alias bc='bc -l "$HOME/.func.bc"'


                And create a file named $HOME/.func.bc that contains (at least):



                # 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))



                A mod function for any number (integer or not) may be defined as:



                # 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) ;


                This definition is perfectly valid and correct by math rules, however, it may become quite confusing when trying to apply it in real cases, just saying.






                share











                share


                share










                answered 1 min ago









                Isaac

                8,58211241




                8,58211241



























                     

                    draft saved


                    draft discarded















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f478192%2fgnu-bc-how-is-the-modulo-with-scale-other-than-0-useful%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Popular posts from this blog

                    How to check contact read email or not when send email to Individual?

                    Bahrain

                    Postfix configuration issue with fips on centos 7; mailgun relay