Je cherche un moyen de dire à awk de faire de l'arithmétique de haute précision dans une opération de substitution. Cela implique de lire un champ d'un fichier et de le remplacer par un incrément de 1% sur cette valeur. Cependant, je perd en précision là-bas. Voici une reproduction simplifiée du problème:
$ echo 0.4970436865354813 | awk '{gsub($1, $1*1.1)}; {print}'
0.546748
Ici, j'ai 16 chiffres après la précision décimale mais awk n'en donne que six. En utilisant printf, j'obtiens le même résultat:
$ echo 0.4970436865354813 | awk '{gsub($1, $1*1.1)}; {printf("%.16G\n", $1)}'
0.546748
Des suggestions sur la façon d'obtenir la précision souhaitée?
gsub
n'est pas nécessaire. Le problème estgsub
sur les chaînes, pas sur les nombres, donc une conversion est effectuée en premier en utilisantCONVFMT
, et la valeur par défaut pour cela est%.6g
.Réponses:
Ou plutôt ici:
est probablement le meilleur que vous puissiez réaliser. Utilisez à la
bc
place pour une précision arbitraire.la source
AWK
vous pouvez utiliser l'-M
indicateur et définir laPREC
valeur sur un grand nombrePour une plus grande précision avec (GNU) awk (avec bignum compilé en) utilisez:
PREC = 100 signifie 100 bits au lieu des 53 bits par défaut.
Si cet awk n'est pas disponible, utilisez bc
Ou vous devrez apprendre à vivre avec l'imprécision inhérente des flotteurs.
Dans vos lignes d'origine, il y a plusieurs problèmes:
Le format de conversion d'une chaîne en un nombre (flottant) est donné par CONVFMT. Sa valeur par défaut est
%.6g
. Cela limite les valeurs à 6 chiffres décimaux (après le point). Ceci est appliqué au résultat du changement gsub de$1
.Le format printf
g
supprime les zéros de fin:Les deux problèmes pourraient être résolus avec:
Ou
Mais ne pensez pas que cela signifie une plus grande précision. La représentation numérique interne est toujours un flotteur en double taille. Cela signifie 53 bits de précision et avec cela, vous ne pouvez être sûr que de 15 chiffres décimaux corrects, même si plusieurs fois jusqu'à 17 chiffres semblent corrects. Voilà un mirage.
La valeur correcte est:
Ce qui pourrait également être calculé avec (GNU) awk si la bibliothèque bignum a été compilée dans:
la source