Печать длинных целых чисел в awk
у меня есть файл с разделителями трубы подачи, который имеет несколько полей. Поскольку мне нужно только несколько, я подумал об использовании awk
чтобы захватить их для моих целей тестирования. Однако, я заметил, что printf
изменяет значение, если я использую "%d"
. Он отлично работает, если я использую "%s"
.
Образец Файла Подачи:
[jaypal:~/Temp] cat temp
302610004125074|19769904399993903|30|15|2012-01-13 17:20:02.346000|2012-01-13 17:20:03.307000|E072AE4B|587244|316|13|GSM|1|SUCC|0|1|255|2|2|0|213|2|0|6|0|0|0|0|0|10|16473840051|30|302610|235|250|0|7|0|0|0|0|0|10|54320058002|906|722310|2|0||0|BELL MOBILITY CELLULAR, INC|BELL MOBILITY CELLULAR, INC|Bell Mobility|AMX ARGENTINA SA.|Claro aka CTI Movil|CAN|ARG|
Я заинтересован в захвате second column
что это 19769904399993903
.
вот мои тесты:
[jaypal:~/Temp] awk -F"|" '{printf ("%dn",)}' temp
19769904399993904 # Value is changed
однако, следующие два теста работает отлично -
[jaypal:~/Temp] awk -F"|" '{printf ("%sn",)}' temp
19769904399993903 # Value remains same
[jaypal:~/Temp] awk -F"|" '{print }' temp
19769904399993903 # Value remains same
так это предел "%d"
не в состоянии обрабатывать длинные целые числа. Если это так, почему он добавляет один к числу, а не может его усекать?
I попробовали это с BSD
и GNU
версии awk
.
Информация О Версии:
[jaypal:~/Temp] gawk --version
GNU Awk 4.0.0
Copyright (C) 1989, 1991-2011 Free Software Foundation.
[jaypal:~/Temp] awk --version
awk version 20070501
6 ответов
Я считаю, что базовый числовой формат в этом случае является двойным IEEE. Таким образом, измененное значение является результатом ошибок точности с плавающей запятой. Если на самом деле необходимо рассматривать большие значения как числовые и поддерживать точную точность, может быть, лучше использовать что-то вроде Perl, Ruby или Python, которые имеют возможности (возможно, через расширения) для обработки арифметики произвольной точности.
начиная с GNU awk 4.1 можно использовать --bignum
или -M
$ awk 'BEGIN {print 19769904399993903}'
19769904399993904
$ awk --bignum 'BEGIN {print 19769904399993903}'
19769904399993903
обновление: последние версии GNU awk поддерживают произвольную арифметику точности. Вижу руководство GNU awk для получения дополнительной информации.
ОРИГИНАЛЬНОЕ СОДЕРЖАНИЕ СООБЩЕНИЯ: XMLgawk поддерживает произвольную арифметику точности на числах с плавающей запятой. Итак, если установка xgawk вариант:
zsh-4.3.11[drado]% awk --version |head -1; xgawk --version | head -1
GNU Awk 4.0.0
Extensible GNU Awk 3.1.6 (build 20080101) with dynamic loading, and with statically-linked extensions
zsh-4.3.11[drado]% awk 'BEGIN {
x=665857
y=470832
print x^4 - 4 * y^4 - 4 * y^2
}'
11885568
zsh-4.3.11[drado]% xgawk -lmpfr 'BEGIN {
MPFR_PRECISION = 80
x=665857
y=470832
print mpfr_sub(mpfr_sub(mpfr_pow(x, 4), mpfr_mul(4, mpfr_pow(y, 4))), 4 * y^2)
}'
1.0000000000000000000000000
на этот ответ частично ответили @Mark Wilkins и @Dennis Williamson, но я обнаружил, что самое большое 64-битное целое число, которое можно обрабатывать без потери точности, - 2^53. Например, справочная страница awk http://www.gnu.org/software/gawk/manual/gawk.html#Integer-Programming
(извините, если мой ответ слишком стар. Подумал, что я все равно поделюсь для следующего человека, прежде чем они потратят слишком много времени на это, как я сделал)
вы сталкиваетесь с проблемы представления с плавающей запятой Awk. Я не думаю, что вы можете найти обходной путь в рамках awk для точного выполнения арифметики на огромных числах.
единственный возможный (и грубый) способ, о котором я могу думать, - это разбить огромное число на меньший кусок, выполнить математику и присоединиться к ним снова или еще лучше использовать языки сценариев Perl/PHP/TCL/bsh и т. д., которые более мощные, чем awk.
используя nawk на Solaris 11, я преобразую число в строку, добавив (concatenate) null в конец, а затем использую %15s
в качестве строки формата:
printf("%15s\n", bignum "")