KA97
KA97

Reputation: 49

How can you force bc to follow the scale?

I want to calculate the percentage of a few numbers upto 2 decimal places. Since my total count is pretty high, dividing 100 by it gives a really small number (0.000..) so for this step I have a large scale of 10. The second step where i multiply the resulting number to calculate the percentage uses scale as 2, but it is ignored as bc uses the first scale of 10. This is the code I have:

mul=$(bc <<< "scale=10; (100/$t)")

while read -r num var
do
perc=$(bc <<< "scale=2; ($num*$mul)")
printf "$var\t$num\t$perc\n" >> ofile
done < counts

How can I get the second calculation to follow the scale and print up to 2 decimal places?

Upvotes: 3

Views: 1088

Answers (4)

Zoltan Peller
Zoltan Peller

Reputation: 421

First of all, the second bc can't use the scale of the first bc, they are two separate instances, bc will not remember the setting of a different process. It's just a coincidence that it ends up being scale 10 at the second run.

However, as JRFerguson wrote, scale is differently calculated for multiplication and division. But if you add a division by 1 to the end of your calculation, the scale settings will be taken into account:

perc=$(bc <<< "scale=2; ($num*$mul/1)")

Upvotes: 0

Michael Rybkin
Michael Rybkin

Reputation: 248

You can sort this problem out by using the following "kludge":

a=3.2222222222
b=24.30123
foo=$(bc <<< "x = $a * $b; scale=2; (x * 100) / 100;")
echo $foo

This code will print out the following output:

78.30

The idea here is that the result of the calculation (x * 100) / 100 is going to be the same number as $a * $b (78.303963332793306 ), but the scale that's going to be applied to it this time will be 2 which in effect will truncate everything you have after two decimal places making it 78.30.

For the reason what happens with the scale of a number that you get as a result of multiplication of two other numbers, see JRFerguson's answer.

The code, in fact, can be made even shorter:

foo=$(bc <<< "scale=2; ($a * $b) / 1")

This is because the new number that you'll get is gong to inherit the global scale of 2 that you had specifically set up.

Upvotes: 1

JRFerguson
JRFerguson

Reputation: 7526

The scale (total number of decimal digits after the decimal point) used with bc operates differently depending on the arithmetic operation involved.

expression*expression

The result shall be the product of the two expressions. If a and b are the scales of the two expressions, then the scale of the result shall be:

min(a+b,max(scale,a,b))

expression/expression

The result shall be the quotient of the two expressions. The scale of the result shall be the value of scale.

This is the reason for the differing behavior between your division and your multiplication in your code.

Upvotes: 1

choroba
choroba

Reputation: 241968

Format the numbers via printf:

printf '%s\t%s\t%.2f\n' "$var" "$num" "$perc" >> ofile

Upvotes: 1

Related Questions