How to round decimals using bc in bash?

152,804

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
Share:
152,804

Related videos on Youtube

blackedx
Author by

blackedx

Updated on September 18, 2022

Comments

  • blackedx
    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
    blackedx almost 12 years
    Thanks for the tip but it doesn't solve what I need. I have to do it just by using bash...
  • Elle
    Elle over 10 years
    The 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
    Aquarius Power about 10 years
    btw, if the number is negative, we have to use -0.5
  • syntaxerror
    syntaxerror over 9 years
    Couldn't get the example to work on the testing console! "Debugging" a little revealed that for e. g. $2 = 3 I had to use echo $(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
    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
    syntaxerror about 9 years
    @muru about your recent edits: herestrings instead of echo .. |, shell arithmetic, what is the point of echo $()? 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
    muru about 9 years
    Herestrings, I agree. But when is echo $() ever needed? That and indentation prompted my edits, the herestrings just happened.
  • Adam Katz
    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 the bc call in the question.
  • Adam Katz
    Adam Katz about 9 years
    This is unnecessarily complicated and does all kinds of extra arithmetic to arrive at the simpler answers provided by migas and zuberuber.
  • Six
    Six over 8 years
    For Python you can just use something like python -c "print(round($num))" where num=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
    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
    RobertG over 8 years
    As noted also in a comment above (askubuntu.com/a/179949/512213), this would behave incorrectly for negative numbers, unfortunately.
  • Jessica P
    Jessica P almost 8 years
    @RobertG: Why? This solution doesn't use +0.5. Try printf "%.2f\n" "$(bc -l <<<"48.86/1.18")" "$(bc -l <<<"-48.86/1.18")" and you will get 41.41 and -41.41.
  • dessert
    dessert over 6 years
    echo $(echo $(printf …)) is unnecessary, just do round(){ printf … ;} and call it with round …. If you want a following linebreak, change %.$2f to %.$2f\\n.
  • dessert
    dessert over 6 years
    Also possible using a pipe: echo "$float/1.18" | bc -l | xargs printf %.2f
  • Admin
    Admin over 6 years
    This looks neat, but bcr "5 / 2" 0 returns 2 instead of 3. Am I missing something?
  • loic.jaouen
    loic.jaouen over 5 years
    it's quite funny to call awk or python to call printf, you'd better do just the same without them: bash echo "4.678923" | xargs printf "%.2f"
  • Marc Tamsky
    Marc Tamsky about 5 years
    I nominate this for "best answer".
  • Torsten Bronger
    Torsten Bronger almost 5 years
    The solution in this answer gives me: bash: printf: 1.69491525423728813559: invalid number, depending on locale.
  • Suuuehgi
    Suuuehgi about 4 years
    printf %.$2f already rounds and hence your round-construction redundant. Just take round() { printf %.$2f $1; }.
  • x-yuri
    x-yuri over 3 years
    Good luck with paying taxes? :) A detailed explanation of your solution would be totally in order.
  • x-yuri
    x-yuri over 3 years
    A detailed explanation would be in order. You could start with what exactly is scale.
  • moonlight
    moonlight over 3 years
    The awk version won't work with negative numbers, but printing a float with zero decimal places will: awk '{printf("%.0f", $1)}'