awk high precision arithmetic
$ echo 0.4970436865354813 | awk -v CONVFMT=%.17g '{gsub($1, $1*1.1)}; {print}'
0.54674805518902947
Or rather here:
$ echo 0.4970436865354813 | awk '{printf "%.17g\n", $1*1.1}'
0.54674805518902947
is probably the best you can achieve. Use bc
instead for arbitrary precision.
$ echo '0.4970436865354813 * 1.1' | bc -l
.54674805518902943
For higher precision with (GNU) awk (with bignum compiled in) use:
$ echo '0.4970436865354813' | awk -M -v PREC=100 '{printf("%.18f\n", $1)}'
0.497043686535481300
The PREC=100 means 100 bits instead of the default 53 bits.
If that awk is not available, use bc
$ echo '0.4970436865354813*1.1' | bc -l
.54674805518902943
Or you will need to learn to live with the inherent imprecision of floats.
In your original lines there are several issues:
- A factor of 1.1 is 10% increase, not 1% (should be a 1.01 multiplier). I'll use 10%.
The conversion format from a string to a (floating) number is given by CONVFMT. Its default value is
%.6g
. That limits the values to 6 decimal digits (after the dot). That is applied to the result of the gsub change of$1
.$ a='0.4970436865354813' $ echo "$a" | awk '{printf("%.16f\n", $1*1.1)}' 0.5467480551890295 $ echo "$a" | awk '{gsub($1, $1*1.1)}; {printf("%.16f\n", $1)}' 0.5467480000000000
The printf format
g
removes trailing zeros:$ echo "$a" | awk '{gsub($1, $1*1.1)}; {printf("%.16g\n", $1)}' 0.546748 $ echo "$a" | awk '{gsub($1, $1*1.1)}; {printf("%.17g\n", $1)}' 0.54674800000000001
Both issues could be solved with:
$ echo "$a" | awk '{printf("%.17g\n", $1*1.1)}' 0.54674805518902947
Or
$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1)}; {printf("%.17f\n", $1)}' 0.54674805518902947
But don't get the idea that this means higher precision. The internal number representation is still a float in double size. That means 53 bits of precision and with that you could only be sure of 15 correct decimal digits, even if many times up to 17 digits look correct. That's a mirage.
$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1}; {printf("%.30f\n", $1)}'
0.546748055189029469325134868996
The correct value is:
$ echo "scale=18; 0.4970436865354813 * 1.1" | bc
.54674805518902943
Which could be also calculated with (GNU) awk if the bignum library has been compiled in:
$ echo "$a" | awk -M -v PREC=100 -v CONVFMT=%.30g '{printf("%.30f\n", $1)}'
0.497043686535481300000000000000