Per una maggiore precisione con (GNU) awk (con bignum compilato in) usare:
$ echo '0.4970436865354813' | awk -M -v PREC=100 '{printf("%.18f\n", $1)}'
0.497043686535481300
Il PREC = 100 significa 100 bit anziché i 53 bit predefiniti.
Se quel awk non è disponibile, usa bc
$ echo '0.4970436865354813*1.1' | bc -l
.54674805518902943
Oppure dovrai imparare a convivere con l'imprecisione intrinseca dei galleggianti.
Nelle linee originali ci sono diversi problemi:
- Un fattore di 1,1 è un aumento del 10%, non dell'1% (dovrebbe essere un moltiplicatore di 1,01). Userò il 10%.
Il formato di conversione da una stringa a un numero (mobile) è dato da CONVFMT. Il suo valore predefinito è %.6g
. Ciò limita i valori a 6 cifre decimali (dopo il punto). Ciò si applica al risultato del cambio gsub di $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
Il formato printf g
rimuove gli zeri finali:
$ 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
Entrambi i problemi potrebbero essere risolti con:
$ echo "$a" | awk '{printf("%.17g\n", $1*1.1)}'
0.54674805518902947
O
$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1)}; {printf("%.17f\n", $1)}'
0.54674805518902947
Ma non pensare che questo significhi maggiore precisione. La rappresentazione del numero interno è ancora un float in doppia dimensione. Ciò significa 53 bit di precisione e con ciò potresti essere sicuro solo di 15 cifre decimali corrette, anche se molte volte fino a 17 cifre sembrano corrette. Questo è un miraggio.
$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1}; {printf("%.30f\n", $1)}'
0.546748055189029469325134868996
Il valore corretto è:
$ echo "scale=18; 0.4970436865354813 * 1.1" | bc
.54674805518902943
Che potrebbe anche essere calcolato con (GNU) awk se la libreria bignum è stata compilata in:
$ echo "$a" | awk -M -v PREC=100 -v CONVFMT=%.30g '{printf("%.30f\n", $1)}'
0.497043686535481300000000000000