Почему не делает awk, делают нуль суммы, но вместо этого очень небольшое число?

Да, это - способ, которым каждый обновляет пакеты через pkg_add. Вопрос был затронут здесь прежде: https://serverfault.com/questions/214611/handling-freebsd-package-upgrades-using-pkg-add.

5
21.12.2015, 05:59
5 ответов
[

] Ваш вопрос - "Почему это происходит?", но ваш неявный вопрос (на который обращались другие): "Как я могу это исправить?"  Вы придумали подход, который вы подняли в комментарии:[

] [
] [

]Так что если я умножу его до 1000, чтобы устранить точку, я смогу получить точный результат, не так ли?[

] [
] [

]Да.  Ну, 10000, так как у тебя четыре десятичных разряда.  Подумайте об этом: [

] [
awk '{ s+=$1*10000; print $1, s/10000 }'
] [

] К сожалению, это не сработает, потому что повреждение уже произошло. как только мы интерпретируем токен (строку) как десятичное число.  Например, []printf "%.20f\n"[] показывает, что входные данные []0.4157[]. на самом деле интерпретируется как 0.415700000000001394.  В этом случае, умножая на 10000, вы получите то, что ожидали: 4157.  Но, например, []0.5973[] = 0.597300000000005311, и умножая это на 10000, получаем 5973.000000000090949470.[

] [

]Поэтому вместо этого пытаемся[

] [
awk '{ s+=int($1*10000); print $1, s/10000 }'
] [

]перевести числа, которые "должны быть" целыми числами (например, 5973.000000000090949470). в соответствующие целые числа (5973).  Но это не удается, так как иногда ошибка преобразования отрицательна; например, []0.7130[] равно 0.71299999999999996714.  А функции [] awk[] [] int([] expr[])[] усекают (в сторону нуля). вместо округления, так что []int(7129.99999999)[] - это 7129. [

] [

] Так что, когда жизнь дает лимоны, вы делаете лимонад.  А когда инструмент дает усеченную функцию, вы округляетесь, добавляя 0.5.  7129.999999+0.5≈7130.49999999, и, конечно, [] int(7130.49999999)[] равно 7130.  Но помните: []int()[] усекает [] в сторону нуля[], и на вашем входе есть отрицательные числа.  Если вы хотите округлить -7129.999999 до -7130, вам нужно [][]вычесть[][] 0.5, чтобы получить -7130.49999999.  Итак, [

] [
awk '{ s+=int($1*10000+($1>0?0.5:-0.5)); print $1, s/10000 }'
] [

], которая добавляет -0.5 к []$1*10000 [], если []$1[] ≤ 0. [

].
1
27.01.2020, 20:31

Для этого можно использовать программу, специально разработанную для работы с арифметическими операциями типа bc:

$ awk '{printf "%s + ",$1}' file | sed 's/\+ $/\n/' | bc
0

Если, как кажется, у вас фиксированное количество знаков после запятой, вы можете просто удалить их, чтобы работать с целыми числами, а затем снова добавить в конце:

$ awk '{sub("0.","",$1);s+=$1;}END{print s/10000}' file
0

или

$ perl -lne 's/0\.//; $s+=$_; END{print $s/10000}' file
0
4
27.01.2020, 20:31

Большинство версий awk имеют команду printf. Вместо

print $1,s

используйте

printf "%.4f %.4f\n",$1,s

и выходы будут округлены до 4 знаков после запятой. Таким образом, вы не увидите большинства ошибок округления.

3
27.01.2020, 20:31

Это не awk уникальная проблема, это еще и проблемы с другими языками программирования. Пример с perl:

$ perl -anle '$sum+=$F[0]}{print $sum' file 
-5.55111512312578e-17

Это проблема представления бесконечного ряда для базы 2 с использованием конечного числа двоичных разрядов. Числа с плавающей точкой не являются целыми числами. Для хранения чисел с плавающей точкой может потребоваться бесконечный объем памяти.

Вы можете прочитать эту статью , чтобы понять больше.

2
27.01.2020, 20:31

Это происходит потому, что компьютер имеет ограниченную точность только при работе с числами. А доступная точность использует двоичный формат для представления числа.

Это делает числа, которые кажутся тривиальными для записи в нашей десятичной системе, могут быть представлены только как приближение (см. запись в Википедии по этому поводу): например, 0,1 (как в 1/10 ) действительно хранится на компьютере как что-то вроде 0,100000001490116119384765625 .

Таким образом, все ваши числа действительно обрабатываются только приближением (если только вам не повезло и у вас есть числа вроде 0,5 , которые могут быть представлены точно ).

Суммирование всех этих приблизительных чисел может в конечном итоге привести к ошибке ! = 0 .

11
27.01.2020, 20:31

Теги

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