Rounding Numbers with Bc in Bash

Rounding Numbers with bc in Bash

Your trick to add 0.0005 is not a bad idea. Though, it doesn't quite work that way. scale is used internally when bc performs some operations (like divisions).

In your case, it would be better to perform the division first, maybe using a large scale or the -l switch to bc1 (if your version supports it), then add 0.0005 and then set scale=3 and perform an operation involving scale internally to have the truncation performed.

Something like:

`a=$sum/$n+0.0005; scale=3; a/1`

Of course, you'll want to proceed differently whether sum is positive or negative. Fortunately, bc has some conditional operators.

`a=$sum/$n; if(a>0) a+=0.0005 else if (a<0) a-=0.0005; scale=3; a/1`

You'll then want to format this answer using printf.

Wrapped in a function round (where you can optionally select the number of decimal figures):

round() {
# $1 is expression to round (should be a valid bc expression)
# $2 is number of decimal figures (optional). Defaults to three if none given
local df=${2:-3}
printf '%.*f\n' "$df" "$(bc -l <<< "a=$1; if(a>0) a+=5/10^($df+1) else if (a<0) a-=5/10^($df+1); scale=$df; a/1")"
}

Try it:

gniourf$ round "(3+3+4)/3"
3.333
gniourf$ round "(3+3+5)/3"
3.667
gniourf$ round "-(3+3+5)/3"
-3.667
gniourf$ round 0
0.000
gniourf$ round 1/3 10
0.3333333333
gniourf$ round 0.0005
0.001
gniourf$ round 0.00049
0.000

1 with the -l switch, scale is set to 20, which should be plenty enough.

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.

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

Round a divided number in Bash

To do rounding up in truncating arithmetic, simply add (denom-1) to the numerator.

Example, rounding down:

N/2
M/5
K/16

Example, rounding up:

(N+1)/2
(M+4)/5
(K+15)/16

To do round-to-nearest, add (denom/2) to the numerator (halves will round up):

(N+1)/2
(M+2)/5
(K+8)/16

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)

Rounding to nearest power of two in bash

Use this function:

power2() { echo "x=l($1)/l(2); scale=0; 2^((x+0.5)/1)" | bc -l; }

Examples

$ power2 11
8
$ power2 12
16
$ power2 13
16
$ power2 16
16
$ power2 63
64

How it works

The echo statement creates a string that bc will interpret as commands. The commands consist of the following:

  • x=l($1)/l(2)

    This sets x to the value of the natural log of the first argument, l($1), divided the natural log of 2, l(2).

  • scale=0

    By setting scale to 0, future divisions will truncate to integer.

  • 2^((x+0.5)/1)

    The expression (x+0.5)/1 rounds x to the nearest integer. We then raise the result of this to the power 2.

Bash, need to count variables, round to 2 and store to variable

Yes, it is working! I did it like this.

Arithmetic operations:

pricevat=$(echo "$vat * ${array[5]}" + ${array[5]} | bc -l)

Round to 3 places:

pricevat=$(printf "%0.3f\n" $pricevat)

If there is another way to do it better or together on one line, let me know please.

Thanks.

Is it possible to use BASH/bc/printf to round a float to its first significant figure?

The following will truncate your numbers to the first non 0 digit:

grep -o "0.0*." <<< "$NUMBER"

For example:

grep -o "0.0*." <<< "0.000003243322"

Prints:

0.000003


Related Topics



Leave a reply



Submit