Szukam sposobu, aby powiedzieć awk, aby wykonywał arytmetykę o wysokiej precyzji w operacji podstawienia. Polega to na odczytaniu pola z pliku i zastąpieniu go przyrostem o 1% tej wartości. Tracę jednak tam precyzję. Oto uproszczona reprodukcja problemu:
$ echo 0.4970436865354813 | awk '{gsub($1, $1*1.1)}; {print}'
0.546748
Tutaj mam 16 cyfr po dokładności dziesiętnej, ale awk daje tylko sześć. Korzystając z printf, otrzymuję ten sam wynik:
$ echo 0.4970436865354813 | awk '{gsub($1, $1*1.1)}; {printf("%.16G\n", $1)}'
0.546748
Wszelkie sugestie, jak uzyskać pożądaną precyzję?
gsub
jest to konieczne. Problem polegagsub
na ciągach, a nie na liczbach, więc konwersja jest wykonywana za pomocąCONVFMT
, a domyślną wartością jest%.6g
.Odpowiedzi:
A raczej tutaj:
jest prawdopodobnie najlepszym, co możesz osiągnąć. Użyj
bc
zamiast tego dla dowolnej precyzji.źródło
AWK
, możesz użyć-M
flagi i ustawićPREC
wartość na dużą liczbęAby uzyskać większą precyzję dzięki (GNU) awk (z kompilowanym bignum) użyj:
PREC = 100 oznacza 100 bitów zamiast domyślnych 53 bitów.
Jeśli ten awk nie jest dostępny, użyj bc
Lub musisz nauczyć się żyć z nieodłączną niedokładnością pływaków.
W twoich oryginalnych wierszach jest kilka problemów:
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
.Format printf
g
usuwa zera końcowe:Oba problemy można rozwiązać za pomocą:
Lub
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ż.
Prawidłowa wartość to:
Który można również obliczyć za pomocą (GNU) awk, jeśli skompilowano bibliotekę bignum:
źródło