39페이지의 섹션 3.2.9에 따름콘파치불・시르스쿠리푸팅구(제5판), 호환되는 쉘 스크립트를 만드는 방법에 대한 참고서에는 제한된 정수 범위를 가진 일부 AWK 구현이 있습니다(내 번역).
예를 들어, AWK에 다음 출력이 표시되지 않습니까?
$ awk 'BEGIN{print 2147483648}' 2.14748e+09 $
이는 0x7FFFFFFF(4바이트 부호 있는 정수의 최대값) 이상의 정수를 처리할 수 없는 구현입니다. 이것이 바로 여러 자리 정수를 다룰 때 주의해야 하는 이유입니다. 계산하지 않고 단지 표시하고 싶다면 문자열로 처리해야 합니다.
하지만 휴대용 스코프가 정확히 무엇인지 책에서 본 적이 없습니다. 그래서 POSIX 문서를 확인하여 알아냈습니다.SUSv2범위가 지정되지 않은 것 같습니다. 다음과 같이 말합니다.
값이 너무 크거나 너무 작아서 표현할 수 없으면 동작이 정의되지 않습니다.
존재하다2004년 판, 그것~인 것 같다정수 및 부동 소수점 값은 각각 long 및 double 유형으로 부호가 지정됩니다("..."는 해당 부분을 생략했음을 의미합니다).
정수 변수 및 상수...는 ISO C 표준 부호 있는 긴 데이터 유형과 동일하게 구현되어야 합니다. 부동 소수점은 ISO C 표준 이중 유형과 동일하게 구현되어야 합니다.
이것은 [-2147483647,+2147483647](PS. Wikipedia에서 범위를 찾았습니다)가 부동 소수점으로 처리되지 않는 이식 가능한 정수 범위라는 것을 의미합니까?
답변1
숫자를 부동 소수점 숫자가 아닌 정수로 처리한다는 것이 정확히 무엇을 의미하는지 궁금합니다.
출력되는 내용을 의미한다면 printf "%d"
gawk, mawk 및 Busybox에서는 -2147483647이 안전한 것처럼 보입니다. 아래 숫자는 mawk에서 -2147483647, Busybox에서 -2147483648로 인쇄되지만 gawk 및 내 Mac에 있는 awk가 무엇이든 실제 값을 인쇄합니다.
반면에 숫자를 사용하여 계산을 수행하는 경우 더 넓은 범위를 얻을 수 있습니다. awk는 무엇이든 사용해야 합니다"ISO C 규격 더블 타입"플랫폼에 있어요. 가장 일반적인 것은 IEEE 754 배정밀도 부동 소수점이지만 필수는 아닙니다.
IEEE double의 경우 가수는 52+1비트이므로 대략 ± 2 53 범위의 모든 정수를 정확하게 표현할 수 있어야 합니다. 숫자를 인쇄하는 것은 출력 형식의 문제일 뿐입니다.
print
( )의 기본 출력 형식 OFMT
은 입니다 %.6g
. 이는 유효 숫자 6자리를 인쇄한다는 의미입니다. 하지만 이것이 전부 진실은 아니기 때문에정수는 정수로 인쇄되어야 합니다., 그러나 awk 버전에 따라 여기서는 정수로 계산됩니다. 일부에서는 다음과 같은 특정 숫자 범위로 제한합니다.
$ busybox awk 'BEGIN { a = 9007199254740992; print a; printf OFMT "\n", a }'
9007199254740992
9.0072e+15
공공의.
$ mawk 'BEGIN { a = 9007199254740992;
print a; printf OFMT "\n", a }'
9.0072e+15
9.0072e+15
OFMT
어쨌든, 예를 들어 %.0f
mawk에서 전체 숫자를 인쇄하도록 변경할 수도 있습니다 .
$ mawk 'BEGIN { OFMT="%.0f"; a = 9007199254740992;
print a; printf OFMT "\n", a }'
9007199254740992
9007199254740992
± 2 53 보다 크면 가장 낮은 비트가 떨어지기 시작하여 문제가 발생합니다.
$ awk 'BEGIN { OFMT="%.0f"; a=9007199254740990;
for (i = 0; i < 6; i++) print a, "+", i, "=", a + i; }'
9007199254740990 + 0 = 9007199254740990
9007199254740990 + 1 = 9007199254740991
9007199254740990 + 2 = 9007199254740992
9007199254740990 + 3 = 9007199254740992
9007199254740990 + 4 = 9007199254740994
9007199254740990 + 5 = 9007199254740996
물론 계산은 에 관계없이 여전히 부동 소수점 숫자를 사용하여 수행되므로 int로 자르지 않는 한 여기서는 을 OFMT
얻습니다 .2000000 = 3 * 666666.666666
1999998 = 3 * 666666
$ awk 'BEGIN{a = 2000000; b = a/3; print 3*b}'
2000000
$ awk 'BEGIN{a = 2000000; b = int(a/3); print 3*b}'
1999998
사용 중인 awk의 원하는 동작을 확인하려면 테스트 스크립트를 만들어야 할 것입니다.
답변2
매우 일반적인 오해를 신속하게 풀고 싶었습니다 . 다른 부동 소수점과 마찬가지로 이중 정밀도 부동 소수점을 mawk
완벽하게 처리할 수 있습니다 . 유일한 주의 사항은 9비트보다 긴 정수 대신 사용하는 것입니다.IEEE 754
awk
%.f
%d %i %u
jot -s $'\n ' -w '%2d' - 1 33 2 | mawk 'BEGIN { printf("\n ") _ += __=_^=FS="^$" ___ = __-(++_)^-(_^_+_+_) OFS = "-st/nd/rd/th-power-of-3 :: " OFMT = CONVFMT = "<( %\047"(_^_)".f )>" } $++NF = _^$__ * ___^(+$__<_^_)'
1-st/nd/rd/th-power-of-3 :: <( 3 )>
3-st/nd/rd/th-power-of-3 :: <( 27 )>
5-st/nd/rd/th-power-of-3 :: <( 243 )>
7-st/nd/rd/th-power-of-3 :: <( 2,187 )>
9-st/nd/rd/th-power-of-3 :: <( 19,683 )>
11-st/nd/rd/th-power-of-3 :: <( 177,147 )>
13-st/nd/rd/th-power-of-3 :: <( 1,594,323 )>
15-st/nd/rd/th-power-of-3 :: <( 14,348,907 )>
17-st/nd/rd/th-power-of-3 :: <( 129,140,163 )>
19-st/nd/rd/th-power-of-3 :: <( 1,162,261,467 )>
21-st/nd/rd/th-power-of-3 :: <( 10,460,353,203 )>
23-st/nd/rd/th-power-of-3 :: <( 94,143,178,827 )>
25-st/nd/rd/th-power-of-3 :: <( 847,288,609,443 )>
27-st/nd/rd/th-power-of-3 :: <( 7,625,597,484,987 )>
29-st/nd/rd/th-power-of-3 :: <( 68,630,377,364,883 )>
31-st/nd/rd/th-power-of-3 :: <( 617,673,396,283,947 )>
33-st/nd/rd/th-power-of-3 :: <( 5,559,060,566,555,523 )>
마지막 숫자 3^33
는 52-
~ 53-bits
(~) 사이이며 52.304 bits
전체 정밀도가 지원하는 가장 큰 3승입니다.754 double fp
2^53 - 1
모든 배정밀도 부동 소수점 소프트웨어에서 직면하는 동일한 제한 사항을 제외하고는 정수 범위와 관련된 사용자 정의 문제가 없을 뿐만 아니라
CONVFMT
또한 멋진 형식 지정 구문을 / 에 직접 추가하여 각 줄에 대한 추가 호출 OFMT
없이 직접 출력을 생성할 수 있는 기능도 있습니다 .sprintf()/printf()
mawk 1.3.4
이는 사용자 정의 컴파일이 아닌 널리 배포된 표준입니다.
mawk -Wv
mawk 1.3.4 20200120
Copyright 2008-2019,2020, Thomas E. Dickey
Copyright 1991-1996,2014, Michael D. Brennan
random-funcs: unknown
regex-funcs: internal
compiled limits:
sprintf buffer 8192
maximum-integer 2147483647
답변3
실제로는삼AWK의 특정 제한 사항.
AWK 정수
정수를 사용하는 경우 그 의미는 다음과 같이 설명됩니다.
AWK에서 값의 내부 표현은 항상 부동 소수점(보통 이중 부동 소수점)입니다. 값에서 문자열을 생성할 때 값이 정수인 경우 %d
사용되는 형식은 무엇이든 상관없습니다 CONVFMT
. 따라서 정수는 텍스트로 인쇄될 때 정수로 유지됩니다.
매뉴얼에서 발췌 mawk
:
expr이 호스트에서 정확한 정수로 표시될 수 없는 경우 expr을 sprintf(CONVFMT, expr)로 대체하여 숫자 표현식을 문자열로 변환한 다음 이를 sprintf("%d", expr)로 변환합니다.
실제로 이는 다음을 통해 알 수 있습니다.
$ mawk 'BEGIN{ CONVFMT="used" ; a=12 ; b = 2^35; c = a "" ; d = b ""; print c, d }'
12 used
또는 보다 일반적인 방법으로:
$ mawk 'BEGIN{ CONVFMT="%2.2f" ; a=2^12 ; b = 2^35; c = a "" ; d = b ""; print c, d }'
4096 34359738368.00
$ mawk 'BEGIN{ CONVFMT="%2.2f" ; a=2^31 ; print a-1"",a"",a+1"" }'
2147483647 2147483648.00 2147483649.00
위에서 본 것처럼 의 값은 2^31-1
정수로 출력되고 나머지 두 개는 부동소수점 숫자로 출력됩니다.
GNU에서는 이 문제가 발생 awk
하지 않습니다 busybox awk
(적어도 64비트 Debian에서는).
뜨다
부동 소수점 숫자는 사용할 수 있는 이진수 수에 따라 제한됩니다. 형식이 어떻게 지정되었는지가 아니라 무엇인지가 문제입니다.
mawk에서는 그보다 큰 값은 2^31
(CONVFMT="%.2f" 사용) 부동 소수점으로 인쇄됩니다.
$ mawk 'BEGIN{ CONVFMT="%.2f"; val=2^53; print val-1"",val"",val+1""}'
9007199254740991.00 9007199254740992.00 9007199254740992.00
그러나 (지수 없이) 가장 큰 정수는 입니다 2^53
. 이는 GNU awk에서도 마찬가지이지만 GNU awk는 이 %.2f
형식을 사용하지 않습니다. 한계를 드러내는 것은 하나를 추가하면 9007199254740992
값이 다시 반복된다는 것입니다. 값은 53비트로 잘립니다.
$ awk 'BEGIN{ CONVFMT="%.2f"; val=2^53; print val-1"",val"",val+1""}'
9007199254740991 9007199254740992 9007199254740992
GMP 라이브러리
GNU awk가 GMP 및 FMPR 라이브러리(현재 표준)로 컴파일되면 모든(합당한 범위 내에서) 정수가 정수로 표시됩니다.
$ awk -M 'BEGIN{ print 2^300; print 2^300+1}'
2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397376
2037035976334486086268445688409378161051468393665936250636140449354381299763336706183397377
이 경우 한도가 상당히 큽니다(구체적인 메모리 한도는 검색하지 않았지만 꼭 있는지 확인하세요. 무한수는 표현이 불가능합니다).
답변4
mawk 'BEGIN { OFS="\t"; OFMT="%\44725.f" ____=___=_*=((_+=_^=_<_)^++_)^(_*_++)*(_______=_) ____*=(_=_______)^(_+_+_) _________=(_______*=_*_)^(++_+—_);—____ for(______+=______=(_+=(_^=_<_)+_)^(_+_+_+_);_<______;_++) { for(__+=__^=_<_;__<_______;__++) { if( (________=_^__)<____ && ___<________ ) { print "",_,__,________ } } } }' | mawk '+(/\t2\t/)<+(/[17]$/)' FS='^$' | mawk '!(NR % 1777)' FS='^$'
2719 4 54,655,872,347,521
5681 3 183,347,236,241
8641 4 5,575,143,118,268,161
15323 3 3,597,753,503,267
24211 3 14,191,822,905,931
33093 3 36,241,688,055,357
41981 3 73,987,497,479,141
50863 3 131,584,858,085,647
59751 3 213,321,944,741,751
68633 3 323,294,970,192,137
77521 3 465,862,871,291,761
86403 3 645,039,730,972,827
95291 3 865,277,983,727,171
104173 3 1,130,486,847,025,717
113061 3 1,445,234,988,645,981
121943 3 1,813,304,024,948,807
130831 3 2,239,401,592,646,191
139713 3 2,727,158,971,340,097
148601 3 3,281,445,502,325,801
157483 3 3,905,719,392,797,587
166371 3 4,605,034,424,282,811
175253 3 5,382,652,995,919,277
184141 3 6,243,836,065,115,221
193023 3 7,191,627,487,303,167
201911 3 8,231,518,131,421,031
코드를 복사하여 직접 실행할 수 있습니다.
말 그대로 내가 설정한 기본값이 아닌 유일한 값은 \t
탭을 출력 구분 기호로 사용하고 쉼표로 정렬된 출력 형식을 사용하는 것입니다.
sprintf()/printf()
코드 어디에서도 한 번도 호출한 적도 없고 외부 유틸리티에 액세스한 적도 없습니다.
mawk-1
나는 다른 사람들과 같습니다:
mawk 1.3.4 20200120
Copyright 2008-2019,2020, Thomas E. Dickey
Copyright 1991-1996,2014, Michael D. Brennan
random-funcs: unknown
regex-funcs: internal
compiled limits:
sprintf buffer 8192
maximum-integer 2147483647