49.765 is my output from a ring of commands. I want to use print f to round it by two decimal figures to 49.77.
What is the code for it?
$ x=49.765
$ printf "%.2f" $(echo "$x + 0.005" | bc)
You have to use external commands because there is no built-in rounding feature in printf(1)
, and the POSIX shell doesn't have built-in floating-point arithmetic.
To round to the nearest decimal digit, you add 0.5 and truncate. To round to the nearest tenth, you divide the "nudge factor" by 10, and so forth.
This lack of built-in facilities is what often pushes people to use something like Perl rather than shell:
$ perl -e 'printf "%.2f", 49.765 + 0.005'
Same thing, but all handled by a single process.
printf
(which convert the numbers to long double), that gives 49.78 for x=49.77 (and 49.77 with zsh / dash's printf
for instance which use doubles). With x=49.79
, that's revered, zsh's printf gives 49.80 while bash/GNU give 49.79.
– Stéphane Chazelas
Sep 04 '22 at 12:52
printf(1)
, try e.g. sh -c 'printf "%.0f\\n" 2.718'
with pretty much any shell. (As far as I read the spec, the %f
specifier isn't required, but even things like Dash do support it. I don't see a reason to assume that any shell which implements it, would implement it incorrectly.)
– ilkkachu
Sep 05 '22 at 18:12
printf "%.2f" $(echo "$x + 0.005" | bc)
fails in the general case, with a few values of $x
, exactly because of the rounding in printf
. E.g. with x=49.772
, printf "%.2f" $(echo "$x + 0.005" | bc)
prints 49.78
, while the correct rounding as per most rules would be 49.77
. The logic of adding 0.5 works when the following action is truncation, not rounding.
– ilkkachu
Sep 05 '22 at 18:12
You can use following command for rounding off.
float number = 49.765; printf("%0.2f", number);
You should be able to get the 2 figures after decimal point.
But this will just print, it will not update the value. If you would like to change the value of the variable then you should use below.
#include <math.h>
float val = 49.765;
float rounded_down = floorf(val * 100) / 100; /* Result: 49.76 */
float nearest = roundf(val * 100) / 100; /* Result: 49.77 */
float rounded_up = ceilf(val * 100) / 100; /* Result: 49.77 */
Notice that there are three different rounding rules you might want to choose: round down (ie, truncate after two decimal places), rounded to nearest, and round up. Usually, you want round to nearest.
As several others have pointed out, due to the quirks of floating point representation, these rounded values may not be exactly the "obvious" decimal values, but they will be very very close.
Capture the output of the "ring of commands" in a variable and use printf
.
$ x=49.765
$ printf '%.2f\n' "$x"
49.76
The rounding is done over the binary representation of the number with the rule of round-to-nearest-ties-to-even. Please understand that the binary representation is not exactly equal to the given number in most cases.
printf
. I do not know of a shell printf that doesn't use nearest-ties-to-even
(the default used in IEEE 754). And even using nearest-ties-up
, the binary representation (in ksh and bash) is 49.764999999999999999444888487687
which is slightly below 49.765
and rounds (the same) to 49.76
. But, of course, he could use dash and get the 49.77
he is asking for with the exact same code (a 53 bit mantissa in dash while it is 64 bit in bash).
– QuartzCristal
Sep 04 '22 at 13:07
zsh -c 'printf "%.30f\n%.2f\n" 49.765 49.765'
print 49.765000000000000568434188608080
and 49.77
. You can try this: https://baseconvert.com/ieee-754-floating-point site where I got this image: https://imgur.com/a/H0PWUBm which clearly shows a number a bit bigger than 49.765
for the double. Maybe your double floats are not equal to my double floats. Are you using an x86 cpu ? @StéphaneChazelas
– QuartzCristal
Sep 04 '22 at 13:44
printf(1)
here (the shell command) orprintf(3)
(the C library function)? My answer below gives the answer forprintf(1)
, which would be on-topic here on Unix.SE. Harshit's answer gives the answer forprintf(3)
, which is really more of a Stack Overflow type of question. – Warren Young Oct 01 '16 at 04:47