Floating Point Rounding in Shell

Rounding up float point numbers bash

In case input contains a number, there is no need for an external command like bc. You can just use printf:

printf "%.3f\n" "$input"

Edit: In case the input is a formula, you should however use bc as in one of the following commands:

printf "%.3f\n" $(bc -l <<< "$input")
printf "%.3f\n" $(echo "$input" | bc -l)

Floating point rounding in shell

It has to do with floating-point, but not with double-precision.

When you write

printf "%0.2f\n" 41.495

on your system, printf first rounds 41.495 to the closest x87 80-bit floating-point number[1]. How does that work? First write 41.495 in binary:

b101001.0111 11101011100001010001 11101011100001010001 11101011100001010001 ...

(the separated groups repeat ad infinitum). Now we round this number to have 64 binary digits:

b101001.0111111010111000010100011110101110000101000111101011100001

This is the number that is actually formatted by printf. Written in decimal, it is exactly:

41.4949999999999999990285548534529880271293222904205322265625

as you can see, it is just a little bit less than 41.495, so when printf rounds it to two fractional digits, it rounds down, and 41.49 is printed.

Now look at 41.485; after rounding to 64 binary digits, we get the value:

41.48500000000000000055511151231257827021181583404541015625

which is just a little bit bigger than 41.485, so printf rounds it up.

On my system, there is a warning about this in the printf manage:

Since the floating point numbers are translated from ASCII to floating-point and then back again, floating-point precision may be lost.


  1. bash doesn't use the x87 format on all operating systems (indeed, it isn't even available on all architectures); on some other systems these values will be interpreted as doubles (and therefore rounded to 53 bits instead of 64), and the results will differ.

How to round a floating point number upto 3 digits after decimal point in bash

What about

a=`echo "5+50*3/20 + (19*2)/7" | bc -l`
a_rounded=`printf "%.3f" $a`
echo "a = $a"
echo "a_rounded = $a_rounded"

which outputs

a         = 17.92857142857142857142
a_rounded = 17.929

?

How do I use floating-point arithmetic in bash?

You can't. bash only does integers; you must delegate to a tool such as bc.

how to round the output in shell?

awk to the rescue!

 awk 'BEGIN      {FS=OFS="|"} 
$NF==$NF+0 {a=$NF*1.21;
r=a-int(a);
if (r<0.225) a=a-r-0.05;
else if (r<0.725) a=a-r+0.50;
else a=a-r+0.95;
$(NF+1)=a} 1'

note that in your example the nearest number for 30.2379 will be 30.50 Perhaps you want to round down?

To round down instead of the nearest, and with a variable price column. The new computed value will be appended to the end of the row.

 awk 'BEGIN    {FS=OFS="|"; k=5} 
$k==$k+0 {a=$k*1.21;
r=a-int(a);
if (r<0.50) a=a-r-0.05;
else if (r<0.95) a=a-r+0.50;
else a=a-r+0.95;
$(NF+1)=a} 1'

Convert floating point numbers to integer without rounding in bash

You could use awk,

$ echo '2.45, 3.56, 54,64' | awk -v FS=" *, *" '{for(i=1;i<=NF;i++){count = count+$i}}END{print count}'
124.01

bash calculation using bc, and round up floating point

As far as I know only division is using the information given by scale.

echo "scale=0; (9 * 150 + 8.092 * 560 + 3.181)/1" | bc

will echo 5884 since the integer part (quotient!) was taken only. To get your desired result (round) you might use:

echo "scale=0; ((9 * 150 + 8.092 * 560 + 3.181)+0.5)/1" | bc

note that this approach will not work for negative numbers! See this post: https://unix.stackexchange.com/a/89843

Bash round whole numbers up, down or to nearest hundreds

It's not entirely clear what is meant by "in Bash", but perhaps one of :

$ cat input
827818
6574762
685038
55326902
$ awk '{printf "%d00\n", $0 / 100}' input
827800
6574700
685000
55326900

or (if all the values are greater than 100!):

while read x; do echo "${x%[0-9][0-9]}00"; done < input

If you want to handle the case where values are less than 100 and deal with negative values, you could do:

while read x; do if test "${x#-}" -gt 100; then echo "${x%[0-9][0-9]}00"; else echo 0; fi; done < input

but it's almost certainly better to stick with awk.



Related Topics



Leave a reply



Submit