Arra keresem a módját, hogy elmondjam az awk-nak, hogy nagy pontosságú aritmetikát végezzen helyettesítési műveletben. Ez azt jelenti, hogy egy mezőt le kell olvasni egy fájlból, és helyettesíteni kell az érték 1% -os növekedésével. Ott azonban elveszítem a pontosságot. Itt van a probléma egyszerűsített reprodukciója:
$ echo 0.4970436865354813 | awk "{gsub($1, $1*1.1)}; {print}" 0.546748
Itt van egy 16 számjegyem a tizedes pontosság után, de az awk csak hatot ad. A printf használatával ugyanazt az eredményt kapom:
$ echo 0.4970436865354813 | awk "{gsub($1, $1*1.1)}; {printf("%.16G\n", $1)}" 0.546748
Van javaslat a kívánt pontosság elérésére?
Megjegyzések
Válasz
$ echo 0.4970436865354813 | awk -v CONVFMT=%.17g "{gsub($1, $1*1.1)}; {print}" 0.54674805518902947
Vagy inkább itt:
$ echo 0.4970436865354813 | awk "{printf "%.17g\n", $1*1.1}" 0.54674805518902947
valószínűleg a legjobb, amit elérhet. Használja helyette az bc parancsot tetszőleges precizitás érdekében.
$ echo "0.4970436865354813 * 1.1" | bc -l .54674805518902943
Megjegyzések
- Ha tetszőleges pontosságot szeretne a
AWKmezőben, használhatja a-Mjelzőt és beállíthatja aPRECérték nagy számra - @RobertBenson, csak a GNU awk-val és csak a legújabb verziókkal (4.1 vagy újabb, tehát nem a válasz írásakor), és csak akkor, ha az MPFR engedélyezve volt a fordításkor idő.
Válasz
A (GNU) awk (a fordított bignummal) nagyobb pontosság érdekében használja:
$ echo "0.4970436865354813" | awk -M -v PREC=100 "{printf("%.18f\n", $1)}" 0.497043686535481300
A PREC = 100 100 bitet jelent az alapértelmezett 53 bit helyett.
Ha az awk nem érhető el, használja a bc
$ echo "0.4970436865354813*1.1" | bc -l .54674805518902943
Vagy meg kell tanulnod élni az úszók eredendő pontatlanságával.
Eredeti soraiban több kérdés is felmerül:
- Az 1.1 tényező 10% -os növekedés, nem 1% (a-nak kell lennie 1,01 szorzó). 10% -ot fogok használni.
-
A karakterláncból (lebegő) számra történő átalakítási formátumot a CONVFMT adja meg. Alapértelmezett értéke:
%.6g. Ez az értékeket 6 tizedesjegyre korlátozza (a pont után). Ez a$1gsub változásának eredményére vonatkozik.$ 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 -
A printf formátum
geltávolítja a záró nullákat:$ 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.54674800000000001Mindkét probléma megoldható a következővel:
$ echo "$a" | awk "{printf("%.17g\n", $1*1.1)}" 0.54674805518902947Vagy
$ echo "$a" | awk -v CONVFMT=%.30g "{gsub($1, $1*1.1)}; {printf("%.17f\n", $1)}" 0.54674805518902947
De ne gondold, hogy ez nagyobb pontosságot jelent. A belső számábrázolás továbbra is dupla méretű úszó. Ez 53 bites pontosságot jelent, és ezzel csak 15 helyes tizedesjegyben lehet biztos, még akkor is, ha sokszor akár 17 számjegy is helyesnek tűnik. Ez a “sa délibáb.”
$ echo "$a" | awk -v CONVFMT=%.30g "{gsub($1, $1*1.1}; {printf("%.30f\n", $1)}" 0.546748055189029469325134868996
A helyes érték:
$ echo "scale=18; 0.4970436865354813 * 1.1" | bc .54674805518902943
Amely akkor is kiszámolandó az (GNU) awk paranccsal, ha a bignum könyvtár a következő fordításban készült:
$ echo "$a" | awk -M -v PREC=100 -v CONVFMT=%.30g "{printf("%.30f\n", $1)}" 0.497043686535481300000000000000
Válasz
Az awk szkriptem nagyobb, mint egy egyvonalas, ezért Stéphane Chazelas és Isaac válaszainak kombinációját használtam:
- Beállítottam a
CONVFMTváltozó, amely globálisan gondoskodik a kimenet formázásáról - A
-Mbignum paramétert aPRECváltozó
Példa-részlet:
#!/usr/bin/awk -M -f BEGIN { FS="<|>" CONVFMT="%.18g" PREC=100 } { if ($2 == "LatitudeDegrees") { CORR = $3 // redacted specific corrections print(" <LatitudeDegrees>" CORR "</LatitudeDegrees>"); } else if ($2 == "LongitudeDegrees") { CORR = $3 // redacted specific corrections print(" <LongitudeDegrees>" CORR "</LongitudeDegrees>"); } else { print($0); } } END { }
Az OP leegyszerűsítette a példáját, de ha a Az awk szkript nem egy egyenes, amelyet nem akarsz printf sekkel szennyezni, hanem a változóban állítsd be az ilyen formátumot. Hasonlóképpen a pontosság, hogy ne vesszen el a tényleges parancssori meghívásban.
gsubfelesleges. A probléma az, hogy agsubkarakterláncokon működik, nem pedig számokon, ezért először egy átalakítást hajtanak végre aCONVFMThasználatával, és ennek alapértelmezett értéke%.6g.