# Float operations with bc not precise?

When I'm performing float operations in shell using bc, the result is not the same if I use a regular calculator. Am I doing something wrong?

For example, I need to find a volume of a sphere. User inputs the radius value.

``````pi = 3.14

volume=\$(echo "scale = 2; (4 / 3) * \$pi * (\$r ^ 3)" | bc)
echo "Volume is \$volume"
``````

If radius = 3, unix returns 112.59, and the calculator 113.1.

• `4/3*3.14*(3^3)` should be `36*3.14 = 113.04`, not `113.1` btw. What's that `calculator` you're using? – Stéphane Chazelas May 2 '16 at 14:05
• @StéphaneChazelas one with more digits of pi, it seems. `4/3*3.14159265358979324*(3^3) = 113.09733552923255664` which rounds up to `113.1` – deamentiaemundi May 2 '16 at 16:51

## 2 Answers

You need to understand the meaning of the scale of an expression in `bc`. `bc` can do arbitrary precision (which doesn't necessarily mean infinite precision) while your calculator will probably have the precision of the `float` or `double` data type of your processor.

In `bc`. The scale is the number of decimal after the dot, so related to the precision. The scale of an expression is determined based on rules that depend on which operator is involved and the `scale` variable (that variable is the one that gives the arbitrary dimension of the precision of `bc` that is, that can make its precision as big as you want).

For instance, the scale of the result of a division is `scale`. So `4/3` when `scale` is 2 is `1.33`, so a very rough approximation of `4/3`. The scale of `x * y` will be `min(a+b,max(scale,a,b))` (where `a` is the scale of `x` and `b` the scale of `y`), so here `2`. so `1.33 * 3.14` will be `4.17`.

For the rules, you can check the POSIX specification for `bc`.

If you want a greater precision, increase `scale`. You can increase it indefinitely. With `bc -l`, `scale` is automatically set to `20`.

``````\$ pi='(a(1)*4)' r=3
\$ \$ echo "(4 / 3) * \$pi * (\$r ^ 3)" | bc -l
113.09733552923255658339

\$ echo "scale=1000; (4 / 3) * \$pi * (\$r ^ 3)" | bc -l
113.0973355292325565846551617980621038310980983775038095550980053230\
81390626303523950609253712316214447357331114478163039295378405943820\
96034211293869262532022821022769726978675980014720642616237749375071\
94371951239736040606251233364163241939497632687292433484092445725499\
76355759335682169861368969085854085132237827361174295734753154661853\
14730175311724413325296040789909975753679476982929026989441793959006\
17331673453103113187002257495740245517842677306806456786589844246678\
87098096084205774588430168674012241047863639151096770218070228090538\
86527847499397329973941181834655436308584829346483609858475202045257\
72294881898002877683392804259302509384339728638724440983234852757850\
73357828522068813321247512718420036644790591105239053753290671891767\
15857867345960859999994142720979823815034238137946746942088054039248\
86988951308030971204086612694295227741563601129621951039171511955017\
31142218396089302929537125655435196874321744263099764736353375070480\
1468800991581641650380680694035580030527317911271523

\$ echo "scale=1; (4 / 3) * \$pi * (\$r ^ 3)" | bc -l
97.2
``````

You can also do all your calculations with a high `scale`, and reduce it in the end for display:

``````\$ echo "scale=10; (4 / 3) * \$pi * (\$r ^ 3)" | bc -l
113.0973355107
\$ echo "scale=100; x = (4 / 3) * \$pi * (\$r ^ 3); scale = 10; x / 1" | bc -l
113.0973355292
``````

You should use a better value for `pi` and allow the scale to be as is defined by default in `bc` (20 digits):

``````\$ echo "r=3; pi=4*a(1); (4/3)*pi*(r^3)" | bc -l
113.09733552923255658339
``````

That is a better way to perform the calculation. Scale is a parameter to define the precision used in the calculation, not a parameter to format the numeric output of the result.

To format the number you may use printf:

``````\$ result="\$(echo "r=3; pi=4*a(1); (4/3)*pi*(r^3)" | bc -l)"
\$ printf '%.2f' "\$result"
113.10
``````

If you get into trouble with the numeric decimal character (`,` or `.`), you may use this version:

``````\$ LC_NUMERIC=C printf '%.2f' "\$result"
113.10
``````

printf rounds the number following the IEEE 754 implementation

Of course, you can force bc to cut the decimals with a final change of the scale:

``````\$ echo "r=3; pi=4*a(1); res=(4/3)*pi*(r^3); scale=2; res/1" | bc -l
113.09
``````

But that is a bad idea in general.