How to round decimals using bc in bash?
Solution 1
A bash round function:
round()
{
echo $(printf %.$2f $(echo "scale=$2;(((10^$2)*$1)+0.5)/(10^$2)" | bc))
};
Used in your code example:
#!/bin/bash
# the function "round()" was taken from
# http://stempell.com/2009/08/rechnen-in-bash/
# the round function:
round()
{
echo $(printf %.$2f $(echo "scale=$2;(((10^$2)*$1)+0.5)/(10^$2)" | bc))
};
echo "Insert the price you want to calculate:"
read float
echo "This is the price without taxes:"
#echo "scale=2; $float/1.18" |bc -l
echo $(round $float/1.18 2);
read -p "Press any key to continue..."
Good luck :o)
Solution 2
Simplest solution:
printf %.2f $(echo "$float/1.18" | bc -l)
Solution 3
Bash/awk rounding:
echo "23.49" | awk '{printf("%d\n",$1 + 0.5)}'
If you have python you can use something like this:
echo "4.678923" | python -c "print round(float(raw_input()))"
Solution 4
Here's a purely bc solution. Rounding rules: at +/- 0.5, round away from zero.
Put the scale you're looking for in $result_scale; your math should be where $MATH is located in the bc command list:
bc <<MATH
h=0
scale=0
/* the magnitude of the result scale */
t=(10 ^ $result_scale)
/* work with an extra digit */
scale=$result_scale + 1
/* your math into var: m */
m=($MATH)
/* rounding and output */
if (m < 0) h=-0.5
if (m > 0) h=0.5
a=(m * t + h)
scale=$result_scale
a / t
MATH
Solution 5
Here's an abbreviated version of your script, fixed to provide the output you want:
#!/bin/bash
float=48.86
echo "You asked for $float; This is the price without taxes:"
echo "scale=3; price=$float/1.18 +.005; scale=2; price/1 " | bc
Note that rounding up to nearest integer is equivalent to adding .5 and taking the floor, or rounding down (for positive numbers).
Also, the scale factor is applied at the time of operation; so
(these are bc
commands, you can paste them into your terminal):
float=48.86; rate=1.18;
scale=2; p2=float/rate
scale=3; p3=float/rate
scale=4; p4=float/rate
print "Compare: ",p2, " v ", p3, " v ", p4
Compare: 41.40 v 41.406 v 41.4067
# however, scale does not affect an entered value (nor addition)
scale=0
a=.005
9/10
0
9/10+a
.005
# let's try rounding
scale=2
p2+a
41.405
p3+a
41.411
(p2+a)/1
41.40
(p3+a)/1
41.41
Related videos on Youtube
blackedx
Updated on September 18, 2022Comments
-
blackedx almost 2 years
A quick example of what I want using bash scripting:
#!/bin/bash echo "Insert the price you want to calculate:" read float echo "This is the price without taxes:" echo "scale=2; $float/1.18" |bc -l read -p "Press any key to continue..." bash scriptname.sh
Assuming that the price is: 48.86 The answer will be:41.406779661 (41.40 actually because I'm using
scale=2;
)My Question is: How I round the second decimal to show the answer in this way?: 41.41
-
blackedx almost 12 yearsThanks for the tip but it doesn't solve what I need. I have to do it just by using bash...
-
Elle over 10 yearsThe python command is more readable and good for quick scripts. Also supports arbitrary digit rounding by adding e.g. ", 3" to the round function. Thanks
-
Aquarius Power about 10 yearsbtw, if the number is negative, we have to use
-0.5
-
syntaxerror over 9 yearsCouldn't get the example to work on the testing console! "Debugging" a little revealed that for e. g.
$2 = 3
I had to useecho $(env printf %.3f $(echo "scale=3;((1000*$1)+0.5)/1000" | bc))
. Mind the env before printf! This'll teach ya again that it's always important to understand what you're copy-pasting from elsewhere. -
syntaxerror over 9 years@Aquarius Power thanks for the inspiration! I've now forked a version of the above script which will work with both negative and positive numbers.
-
syntaxerror about 9 years@muru about your recent edits: herestrings instead of
echo .. |
, shell arithmetic, what is the point ofecho $()
? This is easy to explain: your here strings will always require a writable/tmp
directory! And my solution will also work on a read-only environment, e. g. an emergency root shell where/
is not always writable by default. So there was a good reason why I coded it that way. -
muru about 9 yearsHerestrings, I agree. But when is
echo $()
ever needed? That and indentation prompted my edits, the herestrings just happened. -
Adam Katz about 9 years
echo "$float" |awk '{printf "%.2f", $1/1.18}'
will perform the question's requested math to the requested percision of hundredths. That's as much "using bash" as thebc
call in the question. -
Adam Katz about 9 yearsThis is unnecessarily complicated and does all kinds of extra arithmetic to arrive at the simpler answers provided by migas and zuberuber.
-
Six over 8 yearsFor Python you can just use something like
python -c "print(round($num))"
wherenum=4.678923
. There's no need to muck about with stdin. You can also round to n digits like so:python -c "print(round($num, $n))"
. -
RobertG over 8 years@AquariusPower +1 yes, it's different for negative numbers. To test for a negative (non-integer!) number, I tried a bit and settled for
if [
echo "$1 / 1" | bc` -gt 0 ] ` - is there a more elegant way to check (except parsing the string for "-")? -
RobertG over 8 yearsAs noted also in a comment above (askubuntu.com/a/179949/512213), this would behave incorrectly for negative numbers, unfortunately.
-
Jessica P almost 8 years@RobertG: Why? This solution doesn't use
+0.5
. Tryprintf "%.2f\n" "$(bc -l <<<"48.86/1.18")" "$(bc -l <<<"-48.86/1.18")"
and you will get41.41
and-41.41
. -
dessert over 6 years
echo $(echo $(printf …))
is unnecessary, just doround(){ printf … ;}
and call it withround …
. If you want a following linebreak, change%.$2f
to%.$2f\\n
. -
dessert over 6 yearsAlso possible using a pipe:
echo "$float/1.18" | bc -l | xargs printf %.2f
-
Admin over 6 yearsThis looks neat, but
bcr "5 / 2" 0
returns2
instead of3
. Am I missing something? -
loic.jaouen over 5 yearsit's quite funny to call
awk
orpython
to callprintf
, you'd better do just the same without them:bash echo "4.678923" | xargs printf "%.2f"
-
Marc Tamsky about 5 yearsI nominate this for "best answer".
-
Torsten Bronger almost 5 yearsThe solution in this answer gives me:
bash: printf: 1.69491525423728813559: invalid number
, depending on locale. -
Suuuehgi about 4 years
printf %.$2f
already rounds and hence your round-construction redundant. Just takeround() { printf %.$2f $1; }
. -
x-yuri over 3 yearsGood luck with paying taxes? :) A detailed explanation of your solution would be totally in order.
-
x-yuri over 3 yearsA detailed explanation would be in order. You could start with what exactly is scale.
-
moonlight over 3 yearsThe awk version won't work with negative numbers, but printing a float with zero decimal places will:
awk '{printf("%.0f", $1)}'