Вопрос

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

Это было полезно?

Решение

Use / operator.

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

Другие советы

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

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

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

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

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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top