Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

If the scale is other than zero, calculations with %, such as 3%2 and 46%4, tend to output 0. How is the algorithm designed with the scale other than 0?

bc
scale=10
print 4%3   // output 0
share|improve this question
add comment

3 Answers

up vote 6 down vote accepted

The command manual says this about how BC calculates the modulo:

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.


EDIT: I looked at the source code for GNU BC and found that the mod operator extends the division operator. In other words, the modulo is calculated as a by-product of the division. It relies on integer division to calculate the modulo. When scale is set, however integer division does not take place.

Try this in BC:

bc
scale = 0
print 5/2

scale = 5
print 5/2

you should get:

2        << Integer Division
2.50000  << NOT integer division!

Now let's plug in these figures the way BC does. The manual says it uses a-(a/b)*b to calculate. Let's plug in our two results, the one resulting from integer division and the one with a scale other than 0.

a - ( a/b ) * b
5 - ( 2   ) * 2  = 1  << CORRECT!
5 - ( 2.5 ) * 2  = 0  << VERY WRONG!

Without integer division:

a - ( a/b ) * b == a - (  a  ) == 0

This is why scale must be set to 0 for the modulo to work properly.
The issue seems to arise out of the design of BC and how it handles numbers with a 'scale'. In order for the modulo to work correctly we need integer division.

There are other much more advanced tools that are free and open source for this purpose, and I recommend you use them.

share|improve this answer
    
I am also getting the same results. –  tj111 Aug 28 '09 at 17:25
    
Your scale is 0, not "other than zero". Please, set it with "scale=10", for example, and then try "3%2". –  user3672 Aug 28 '09 at 17:54
    
thanks for the clarification. I'll update my answer. –  jweede Aug 28 '09 at 18:10
2  
when it says 'scale' with no parenthesis, it refers to the global variable 'scale'. –  jweede Aug 31 '09 at 11:55
1  
I'm not sure why it needs to be scale+scale(b) since the scale of a/b should generally be zero for it to give meaningful output. –  jweede Sep 3 '09 at 13:19
show 7 more comments

user272970's answer is great. Here's a tweak to it:

define int(x) { auto oldscale; oldscale=scale; scale=0; x=x/1; scale=oldscale; return( x ); }
define fmod(x,y) { auto oldscale; oldscale=scale; scale=1000; x = x - y * int(x/y); scale=oldscale; return( x ); }

This (using auto oldscale) makes oldscale local to the function. Without that, setting oldscale in int() from fmod() will overwrite the oldscale that is trying to be saved in fmod(), leaving scale set to 1000 instead of whatever you had before calling fmod().

I added these functions to ~/.bcrc and set the BC_ENV_ARGS environment variable to ~/.bcrc. That will load these functions every time you run bc. So now I can just run fmod(x,y) any time I'm in bc without having to manually define those functions every time.

p.s. scale of 1000 might be overkill in most cases

share|improve this answer
add comment

I solved it this way:

integer

define int(x) { oldscale=scale; scale=0; x=x/1; scale=oldscale; return( x ); }

modulo

define mod(x,y) { oldscale=scale; scale=1000; x = x - y * int(x/y); scale=oldscale; return( x ); }

HTH

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.