问题
So I am trying to use bc to calculate some logarithms but I also need to use it to calculate the modulus for something. Whilst making my script, I launched bc to test it.
Without any flags, bc <<< "3%5" of course returns 3.
But with bc -l (loads math library so I can compute logarithms) any calculation of a%b returns 0 where a and b can be any number but 0.
What's happening?
回答1:
That's 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 you run bc with the -l flag, scale is set to 20. To fix this:
bc -l <<< "oldscale=scale; scale=0; 3%5; scale=oldscale; l(2)"
We first save scale in variable oldscale, then set scale to 0 to perform some arithmetic operations, and to compute a ln we set scale back to its old value. This will output:
3
.69314718055994530941
as wanted.
回答2:
According to the 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 is that it tries to evaluate a-(a/b)*b using the current scale settings. The default 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 see how it works, try some other fractions:
$ bc -l
1%3
.00000000000000000001
To make a long story short, just compare three outputs:
Default scale with -l enabled (20):
scale
20
3%5
0
1%4
0
Let's set scale to 1:
scale=1
3%5
0
1%4
.2
Or to zero (default without -l):
scale=0
3%5
3
1%4
1
回答3:
You could define a function that works in math mode by temporarily setting scale to zero.
I have bc aliased like this:
alias bc='bc -l ~/.bcrc'
Thus ~/.bcrc is evaluated before any other expressions, so you can define functions in ~/.bcrc. For example a modulus function:
define mod(x,y) {
tmp = scale
scale = 0
ret = x%y
scale = tmp
return ret
}
Now you can do modulo like this:
echo 'mod(5,2)' | bc
Output:
1
回答4:
man bc :
If bc is invoked with the -l option, a math library is preloaded and the default scale is set to 20.
So maybe you should set the scale to 0 :
#bc
scale=0
10%3
1
回答5:
For what it's worth, when I use bc -l, I have the following functions defined:
define trunc(x) {auto s; s=scale; scale=0; x=x/1; scale=s; return x}
define mod(x,y) {return x-(y*trunc(x/y))}
That should give you a proper MOD function, while keeping your scale intact. Of course, it won't help if you NEED to use the % operator for some reason.
(That TRUNC function is quite handy too, forming the basis for many other useful functions that are outside the scope of this answer.)
来源:https://stackoverflow.com/questions/27470210/bash-bc-modulo-does-not-work-with-l-flag