арифметика высокой точности awk

Угадайте, что я использовал восьмеричный слишком долго.

7 rwx (сделайте что-либо с ним), 5 rx (должен считать его для выполнения его), 6 wr (любой файл данных, который необходимо изменить), 4 r (мы позволим Вам посмотреть на него), и 0 - (извините, ничто здесь для наблюдения). И порядок - Я, Мы, Все. Это основные комбинации.

755 я могу изменить и выполнить его, все остальные могут выполнить его.

644 я могу изменить его, все остальные могут считать его.

444 Только для чтения для всех, мы через здесь.

500 я могу выполнить его, не хотите, чтобы это изменилось, все остальные руки прочь.

Для меня это коротко к точке. 9 символов и спецификация файла и движение.

11
29.11.2012, 01:40
2 ответа
$ echo 0.4970436865354813 | awk -v CONVFMT=%.17g '{gsub($1, $1*1.1)}; {print}'
0.54674805518902947

Или скорее здесь:

$ echo 0.4970436865354813 | awk '{printf "%.17g\n", $1*1.1}'
0.54674805518902947

является, вероятно, лучшим, можно достигнуть. Использовать bc вместо этого для произвольной точности.

$ echo '0.4970436865354813 * 1.1' | bc -l
.54674805518902943
12
27.01.2020, 19:58
  • 1
    , Если Вы хотите произвольную точность в AWK можно использовать -M флаг и набор PREC оцените большому количеству –  Robert Benson 03.04.2018, 23:09
  • 2
    @RobertBenson, только с GNU awk и только с последними версиями (4.1 или выше, таким образом, не в то время, когда ответ был записан) и только когда MPFR был включен во время компиляции все же. –  Stéphane Chazelas 03.04.2018, 23:37

Для более высокой точности с (GNU )awk (с bignum, скомпилированным в ), используйте:

$ echo '0.4970436865354813' | awk -M -v PREC=100 '{printf("%.18f\n", $1)}'
0.497043686535481300

PREC=100 означает 100 бит вместо 53 бит по умолчанию.
Если этот awk недоступен, используйте bc

$ echo '0.4970436865354813*1.1' | bc -l
.54674805518902943

Или вам придется научиться жить с неточностью, присущей поплавкам.


В ваших исходных строках есть несколько вопросов:

  • Коэффициент 1,1 означает увеличение на 10%, а не 1% (должен быть множителем 1,01 ). Я буду использовать 10%.
  • Формат преобразования строки в число с плавающей запятой ()задается функцией CONVFMT. Его значение по умолчанию — %.6g. Это ограничивает значения до 6 десятичных цифр (после точки ). Это применяется к результату изменения 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
    
  • Формат printf gудаляет конечные нули:

    $ 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
    

    Обе проблемы можно решить с помощью:

    $ echo "$a" | awk '{printf("%.17g\n", $1*1.1)}'
    0.54674805518902947
    

    или

    $ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1)}; {printf("%.17f\n", $1)}'
    0.54674805518902947 
    

Но не думайте, что это означает более высокую точность. Представление внутреннего числа по-прежнему является числом с плавающей запятой двойного размера. Это означает 53 бита точности, и при этом вы можете быть уверены только в 15 правильных десятичных цифрах, даже если много раз до 17 цифр выглядят правильными. Это мираж.

$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1}; {printf("%.30f\n", $1)}'
0.546748055189029469325134868996

Правильное значение:

$ echo "scale=18; 0.4970436865354813 * 1.1" | bc
.54674805518902943

Это можно было бы также вычислить с помощью (GNU )awk, если библиотека bignum была скомпилирована в:

$ echo "$a" | awk -M -v PREC=100 -v CONVFMT=%.30g '{printf("%.30f\n", $1)}'
0.497043686535481300000000000000
4
27.01.2020, 19:58

Теги

Похожие вопросы