Bash, bc modulo does not work with -l flag

So I am trying to use bc to calculate some logarithms, but I also need to use it to calculate the module for something. While my script, I ran bc to test it.

Without any flags, bc <<< "3%5" , of course, returns 3 .

But with bc -l (loads the math library so I can calculate the logarithms), any calculation of a%b returns 0 , where a and b can be any number, but 0 .

What's happening?

+6
source share
4 answers

This is because from the manual:

  expr % expr The result of the expression is the "remainder" and it is com‐ puted in the following way. To compute a%b, first a/b is com‐ puted 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. 

When bc starts up with the -l flag, it is set to 20 . To fix this:

 bc -l <<< "oldscale=scale; scale=0; 3%5; scale=oldscale; l(2)" 

First, save scale in the oldscale variable, then set scale to 0 to perform some arithmetic operations, and to calculate a ln we will return the old scale value. This will output:

 3 .69314718055994530941 

optional.

+11
source

According to bc manual

  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. 

So what happens, he tries to evaluate a-(a/b)*b using the current scale settings. The default value of scale is 0, so you get the remainder. When you run bc -l , you get scale=20 , and the expression a-(a/b)*b evaluates to zero when using 20 fractional digits.

To find out how this works, try other fractions:

 $ bc -l 1%3 .00000000000000000001 

To make a long story short, simply compare three outputs:

By default, scale with -l (20) enabled:

 scale 20 3%5 0 1%4 0 

Set scale to 1:

 scale=1 3%5 0 1%4 .2 

Or to zero (by default without -l ):

 scale=0 3%5 3 1%4 1 
+7
source

You can define a function that works in math mode by temporarily setting scale to zero.

I have a bc alias:

 alias bc='bc -l ~/.bcrc' 

Thus, ~/.bcrc is evaluated before any other expressions, so you can define functions in ~/.bcrc . For example, a module function:

 define mod(x,y) { tmp = scale scale = 0 ret = x%y scale = tmp return ret } 

Now you can do modulo as follows:

 echo 'mod(5,2)' | bc 

Output:

 1 
+3
source

man bc:

If bc is called with the -l option, the math library is preloaded and the default value is 20.

So, perhaps you should set the scale to 0:

 #bc scale=0 10%3 1 
+2
source

Source: https://habr.com/ru/post/979575/


All Articles