AWK에서 정수 값의 이식 가능한 범위는 무엇입니까?

AWK에서 정수 값의 이식 가능한 범위는 무엇입니까?

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어쨌든, 예를 들어 %.0fmawk에서 전체 숫자를 인쇄하도록 변경할 수도 있습니다 .

$ 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.6666661999998 = 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 754awk%.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^3352-~ 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

관련 정보