Aby uzyskać większą precyzję dzięki (GNU) awk (z kompilowanym bignum) użyj:
$ echo '0.4970436865354813' | awk -M -v PREC=100 '{printf("%.18f\n", $1)}'
0.497043686535481300
PREC = 100 oznacza 100 bitów zamiast domyślnych 53 bitów.
Jeśli ten awk nie jest dostępny, użyj bc
$ echo '0.4970436865354813*1.1' | bc -l
.54674805518902943
Lub musisz nauczyć się żyć z nieodłączną niedokładnością pływaków.
W twoich oryginalnych wierszach jest kilka problemów:
- Współczynnik 1,1 to wzrost o 10%, a nie 1% (powinien być mnożnikiem 1,01). Użyję 10%.
Format konwersji łańcucha na liczbę zmiennoprzecinkową podaje CONVFMT. Jego wartość domyślna to %.6g
. To ogranicza wartości do 6 cyfr dziesiętnych (po kropce). Jest to stosowane do wyniku zmiany gsub $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
Format printf g
usuwa zera końcowe:
$ 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
Oba problemy można rozwiązać za pomocą:
$ echo "$a" | awk '{printf("%.17g\n", $1*1.1)}'
0.54674805518902947
Lub
$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1)}; {printf("%.17f\n", $1)}'
0.54674805518902947
Ale nie myśl, że oznacza to wyższą precyzję. Wewnętrzna reprezentacja liczb jest wciąż zmienna podwójna. Oznacza to 53 bity precyzji, dzięki czemu można mieć pewność tylko 15 prawidłowych cyfr dziesiętnych, nawet jeśli wiele razy do 17 cyfr wygląda poprawnie. To miraż.
$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1}; {printf("%.30f\n", $1)}'
0.546748055189029469325134868996
Prawidłowa wartość to:
$ echo "scale=18; 0.4970436865354813 * 1.1" | bc
.54674805518902943
Który można również obliczyć za pomocą (GNU) awk, jeśli skompilowano bibliotekę bignum:
$ echo "$a" | awk -M -v PREC=100 -v CONVFMT=%.30g '{printf("%.30f\n", $1)}'
0.497043686535481300000000000000