Печать длинных целых чисел в 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 "")