bc truncate floating point number
Asked Answered
D

6

30

How do I truncate a floating point number using bc

e.g if I do

echo '4.2-1.3' | bc

which outputs 2.9 how I get it to truncate/use floor to get 2

Decury answered 13/12, 2013 at 3:44 Comment(0)
G
35

Use / operator.

echo '(4.2-1.3) / 1' | bc
Gland answered 13/12, 2013 at 3:46 Comment(3)
That doesn't seem to always work: echo '(l(101)/l(10)) / 1' | bc -l returns a float.Miniaturize
it would still work if you do echo 'scale=0; (l(101)/l(10)) / 1' | bc -lLakin
@JohnnyEverson that's because you're passing bc the -l flag which loads the math library and sets scale to 20. Otherwise, by default the scale is zero.Hampden
E
19

Dividing by 1 works ok if scale is 0 (eg, if you start bc with bc and don't change scale) but fails if scale is positive (eg, if you start bc with bc -l or increase scale). (See transcript below.) For a general solution, use a trunc function like the following:
define trunc(x) { auto s; s=scale; scale=0; x=x/1; scale=s; return x }

Transcript that illustrates how divide by 1 by itself fails in the bc -l case, but how trunc function works ok at truncating toward zero:

> bc -l
bc 1.06.95
[etc...]
for (x=-4; x<4; x+=l(2)) { print x,"\t",x/1,"\n"}
-4  -4.00000000000000000000
-3.30685281944005469059 -3.30685281944005469059
-2.61370563888010938118 -2.61370563888010938118
-1.92055845832016407177 -1.92055845832016407177
-1.22741127776021876236 -1.22741127776021876236
-.53426409720027345295  -.53426409720027345295
.15888308335967185646   .15888308335967185646
.85203026391961716587   .85203026391961716587
1.54517744447956247528  1.54517744447956247528
2.23832462503950778469  2.23832462503950778469
2.93147180559945309410  2.93147180559945309410
3.62461898615939840351  3.62461898615939840351
define trunc(x) { auto s; s=scale; scale=0; x=x/1; scale=s; return x }
for (x=-4; x<4; x+=l(2)) { print x,"\t",trunc(x),"\n"}
-4  -4
-3.30685281944005469059 -3
-2.61370563888010938118 -2
-1.92055845832016407177 -1
-1.22741127776021876236 -1
-.53426409720027345295  0
.15888308335967185646   0
.85203026391961716587   0
1.54517744447956247528  1
2.23832462503950778469  2
2.93147180559945309410  2
3.62461898615939840351  3
Erasmo answered 13/12, 2013 at 8:42 Comment(1)
one liner ex.: bc <<< "scale=10;f=(3/55);scale=0;(312*f)/1"Strengthen
L
11

Try the following solution. It will truncate anything after the decimal point without a problem:

echo 'x = 4.2 - 1.3; scale = 0; x / 1' | bc -l
echo 'x = l(101) / l(10); scale = 0; x / 1' | bc -l

You can make the code a tad shorter by performing calculations directly on the numbers:

echo 'scale = 0; (4.2 - 1.3) / 1' | bc -l
echo 'scale = 0; (l(101) / l(10)) / 1' | bc -l

In general, you can use this function to get only the integer part of a number:

define int(x) {
    auto s;
    s = scale;
    scale = 0;
    x /= 1; /* This will have the effect of truncating x to its integer value */
    scale = s;
    return (x);
}

Save that code into a file (let's call it int.bc) and run the following command:

echo 'int(4.2 - 1.3);' | bc -l int.bc
Labialized answered 29/11, 2018 at 4:58 Comment(0)
G
5

The variable governing the amount of decimals on division is scale.

So, if scale is 0 (the default), dividing by 1 would truncate to 0 decimals:

$ echo '(4.2-1.3) / 1 ' | bc
2

In other operations, the number of decimals is calculated from the scale (number of decimals) of each operand. In add, subtract and multiplication, for example, the resulting scale is the biggest of both:

$ echo ' 4.2 - 1.33333333 ' | bc
2.86666667

$ echo ' 4.2 - 1.333333333333333333 ' | bc
2.866666666666666667

$ echo ' 4.2000 * 1.33 ' | bc
5.5860

Instead, in division, the number of decimals is strictly equal to th evalue of the variable scale:

$ echo 'scale=0;4/3;scale=3;4/3;scale=10;4/3' | bc
1
1.333
1.3333333333

As the value of scale has to be restored, it is better to define a function (GNU syntax):

$ echo ' define int(x){ os=scale;scale=0;x=x/1;scale=os;return(x) } 
         int( 4.2-1.3 )' | bc
2

Or in older POSIX language:

$ echo ' define i(x){
             o=scale;scale=0;x=x/1;scale=o;return(x)
         } 
         i( 4.2-1.3 )' | bc
2
Gripper answered 27/4, 2020 at 21:45 Comment(0)
H
0

You say:

truncate/use floor

And those are not the same thing in all cases. The other answers so far only show you how to truncate (i.e. "truncate towards zero" i.e. "discard the part after the decimal").

For negative numbers, the behavior is different.

To wit:

truncate(-2.5) = -2
floor(-2.5) = -3

So, here is a floor function for bc:


# Note: trunc(x) is defined as noted elsewhere in the other answers

define floor(x) {
    auto t
    t=trunc(x)
    if (t>x) {
        return t-1
    } else {
        return t 
    } 
}

Aside:

You can put this, and other helper functions, in a file. For instance, I have this alias in my shell:

alias bc='bc -l ~/.bcinit'

And so whenever I run bc, I get all my utility functions from ~/.bcinit available by default.

Also, there is a good list of bc functions here: http://phodd.net/gnu-bc/code/funcs.bc

Health answered 4/6, 2022 at 20:17 Comment(0)
W
0

You may do something like this:

$ printf "%.2f\n" $(echo "(4530 / 4116 - 1) * 100" | bc -l)
10.06

Here I am trying to find the % change. Not purely bc though.

Walkerwalkietalkie answered 19/6, 2022 at 0:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.