awk의 "inf"는 "-inf"처럼 작동하지 않습니다.

awk의 "inf"는 "-inf"처럼 작동하지 않습니다.

단일 열 번호 파일이 주어지면 호출될 때 f다음 Awk 코드는 최대값을 반환합니다.

cat f | awk    '   BEGIN {max = -inf}
                       {if ($1>max) max=$1} 
                   END { print max }
               '

최소값을 구하는 동일한 방법으로 결과가 나오지 않습니다.

cat f | awk '
               BEGIN  {min = inf}
                  {if ($1<min) min=$1} 
               END {print min}
            '

그러나 을 inf사용하지 않고 에서 시작하는 min = [some large number]경우 숫자가 충분히 크면(파일 내용에 따라) 수정된 코드가 작동합니다.

왜 작동하지 않으며 파일에 무엇이 있는지 알지 않고도 사례를 사례처럼 처리할 inf수 있는 방법이 있습니까 ?minmax

답변1

이것실제가장 좋은 해결 방법은 가상의 "최소" 또는 "최대" 숫자(이 경우 사용 중인 프레임워크에서 달성하지 못할 수 있음 awk)가 아닌 다음을 사용하여 최대/최소 값을 초기화하는 것입니다.실제데이터. 이렇게 하면 항상 의미 있는 결과가 보장됩니다.

귀하의 경우 규칙을 추가하여 처음 발견된 값(즉, 첫 번째 행의 항목)을 초기화 max하고 각각 사용할 수 있습니다.min

NR==1{min=$1}

당신의 스크립트에 awk. 그런 다음 첫 번째 값이 이미 최소값인 경우 후속 테스트에서는 이를 다루지 않고 결국 올바른 결과를 생성합니다. 최대값 검색에도 동일하게 적용되므로 결합 검색에서는 다음을 선언할 수 있습니다.

NR==1{max=min=$1}

inf귀하의 방법이 작동하지 않는 이유는 무엇입니까?그리고 @steeldriver가 귀하의 질문에 대한 의견에 좋은 설명을 제공한 awk것 같습니다 -inf. 완전성을 위해 요약하겠습니다.

  • 에서 awk변수는 "동적으로 유형이 지정"됩니다. 즉, 사용법에 따라 모든 것이 문자열 또는 숫자가 될 수 있습니다(그러나 awk마지막으로 사용된 내용을 "기억"하고 다음 작업을 위해 해당 정보를 유지합니다).
  • 코드에서 변수와 관련된 산술 연산이 발견될 때마다 awk해당 변수의 내용을 숫자로 해석하여 연산을 수행하려고 시도하며, 성공하면 거기에서 변수가 숫자로 입력됩니다.
  • 아무것도 할당되지 않은 변수의 기본값은 빈 문자열이며 산술 연산에서 0으로 해석됩니다.
  • 이것변수 이름(*) inf특별한 의미가 없으므로 awk이렇게 사용하면 와 같은 산술식에서 0으로 평가되는 빈 변수이다 -inf. 따라서 데이터가 모두 양수인 경우 max변수가 0으로 초기화된 "최대 검색"이 작동합니다(따라서 음수가 아닌 가장 작은 숫자).-inf-inf
  • 그러나 "최소 검색" 문제에서는 이 빈 문자열을 숫자로 자동 변환하는 것을 보장하는 산술 연산이 없기 때문에 초기화는 변수를 빈 문자열로 min초기화합니다 .inf
  • 그래서 다음 비교에서는

    if ($1<min) min=$1
    

    입력은 $1문자열 값과 비교되므로 문자열 awk로 처리되어 실행됩니다.$1사전 편찬숫자보다는 비교해보세요.

  • 그러나 사전 편찬의 관점에서 보면,아무것도 없다빈 문자열보다 "작다".min 안 돼요새로운 값이 할당됩니다. 따라서 이 END부분에서는 다음과 같이 명시한다.

    print min
    

    (여전히) 빈 문자열을 인쇄합니다.

(*) 바라보다스티븐 키트의 답변어떻게내용이 포함된 문자열"inf"실제로 이해가 될 수 있습니다 awk.

답변2

infGNU AWK의 기본 비 POSIX 모드에서는 특별한 의미가 없기 때문에 귀하의 접근 방식이 작동하지 않습니다 . 결과적으로는 변수명으로 해석되며 변수에 아무 것도 설정되지 않았으므로 그 값은 산술 문맥에서는 0, 문자열 문맥에서는 빈 문자열이다. 따라서 코드는 양수의 최대값( max산술 컨텍스트에서 초기화되기 때문에)만 찾고 최소값( min문자열 컨텍스트에서 초기화되기 때문에)은 찾지 않습니다.관리자 꿀벌의 답변더 알아보기.

파일(또는 스트림)의 최소 및/또는 최대 값을 결정하려면 다음에 제공된 조언을 따라야 합니다.관리자 꿀벌의 답변.

그러나 GNU AWK를 사용하는 경우 log(0)양수 또는 음수 무한대에서 변수 초기화를 계산하고 이를 메서드와 비슷한 방식으로 사용할 수 있습니다.

BEGIN { max = log(0) }
$1 > max { max = $1 }
END { print max }
BEGIN { min = -log(0) }
$1 < min { min = $1 }
END { print min}

첫 번째 행의 값을 초기화하는 것과 비교할 때 이 접근 방식의 유일한 장점은 처리되는 값이 없을 때 고유한 결과를 제공할 수 있다는 것입니다. 양수 또는 음수 무한대는 결과적으로 값이 표시되지 않았음을 나타내는 신뢰할 수 있는 지표가 됩니다. (첫 번째 줄에서 초기화할 때 0 대신 빈 문자열을 확인하는 것을 포함하여 이를 확인하는 다른 방법이 있습니다.)

예를 들어 , POSIX 모드( POSIXLY_CORRECT=1)에서 GNU AWK를 사용하거나 다른 POSIX 호환 AWK 인터프리터를 사용하세요.mawk"inf"덕분에 산술 문맥에서 무한대가 생성됩니다.strtod:

BEGIN { max = "-inf" + 0 }
$1 > max { max = $1 }
END { print max }
BEGIN { min = "+inf" + 0 }
$1 < min { min = $1 }
END { print min}

답변3

실제로 무한대에는 -inf +infand inf, 및 의 세 가지 값이 있습니다. 간단한 문제에 더 많은 복잡성을 추가하기 위해 awk에는 인용된 코드 상수와 인용되지 않은 코드 상수가 있습니다.

무슨 뜻인지 설명하려면 다음을 시도해 보십시오(awk 4.2.1(현재 Debian 10)의 쉘 코드).

for cmd in original-awk "busybox awk" mawk nawk awk; do
    printf '%-6.5s' "$cmd"
    $cmd 'BEGIN {
        a="-inf";b="+inf";c="inf";
        d= -inf ;e= +inf; f= inf;
        printf "-∞%4s%4s +∞%4s%4s ∞%4s%4s | -∞%4s%4s +∞%4s%4s ∞%4s%4s\n",a,a+0,b,b+0,c,c+0,d,d+0,e,e+0,f,f+0}
    ' file

얻으려면 :

bawk  -∞-inf-inf +∞+inf inf ∞ inf inf | -∞   0   0 +∞       0 ∞       0
busyb -∞-inf-inf +∞+inf inf ∞ inf inf | -∞   0   0 +∞   0   0 ∞       0
mawk  -∞-inf-inf +∞+inf inf ∞ inf inf | -∞   0   0 +∞   0   0 ∞       0
nawk  -∞-inf-inf +∞+inf inf ∞ inf   0 | -∞   0   0 +∞   0   0 ∞       0
gawk  -∞-inf-inf +∞+inf inf ∞ inf   0 | -∞   0   0 +∞   0   0 ∞       0

이 표는 인용된 변수 할당과 인용되지 않은 변수 할당(abcdef)을 보여줍니다.
각 경우에 대해 awk는 값을 읽고 숫자(var+0)로 변환합니다.

"-inf"이는 a가 숫자인 경우에도 그대로 유지되고 a는 숫자 (부호 없이) "+inf"로 변환되며 참조된 a는 구현에 따라 또는 이 될 수 있음을 의미합니다(nawk 및 gawk에서는 0 ) .inf"inf"inf0

따옴표가 없으면 -inf둘 다 +inf됩니다 ( 빈 문자열 ""로 해석되어 로 변환되는 0bawk 제외 ).+∞0

이상한 점은 따옴표가 없으면 모든 것이 inf빈 문자열로 해석된다는 것입니다.

그러나 모두 따옴표 없이 -inf사용하면 +inf0 이 됩니다.infvar+0

따라서 원하는 작업에는 따옴표가 필요하며 "-inf"절대 "+inf"다음이 필요하지 않습니다 inf.

cat file | awk  '  BEGIN { max = "-inf"+0; min = "+inf"+0 }
                         { if ($1>max) max=$1
                           if ($1<min) min=$1
                         } 
                   END   { print min, max }
                '

아마도 이를 이해하는 더 간단한(이식 불가능한 방법)은 다음과 같습니다.

gawk 'BEGIN{
               a="-inf";b="+inf";c="inf";
               d= -inf ;e= +inf; f= inf;

               print a,   typeof(a),   b,   typeof(b),   c,   typeof(c)
               print a+0, typeof(a+0), b+0, typeof(b+0), c+0, typeof(c+0)

               print d,typeof(d),e,typeof(e),f,typeof(f)
               print d+0,typeof(d+0),e+0,typeof(e+0),f+0,typeof(f+0)
      }'

다음을 인쇄합니다:

-inf string +inf string inf string
-inf number inf number 0 number
0 number 0 number  unassigned
0 number 0 number 0 number

물론 정확하고 이식 가능한 해결책은 max처음부터 및 변수에 값을 할당하는 것입니다.min

cat file | awk  '  NR==1 { min = max = $1 }
                         { if ($1>max) max=$1
                           if ($1<min) min=$1
                         } 
                   END   { print min, max }
                '

---

설명하다awk 매뉴얼에서예:

  • --posix명령줄 옵션을 사용하면 gawk"그대로 놔둘" 수 있습니다. 문자열 값은 시스템 라이브러리의 strtod() 함수에 직접 전달되며, 성공적으로 숫자 값을 반환하면 해당 값이 사용됩니다. 정의에 따르면 결과는 다른 시스템에 이식될 수 없습니다. 그들은 또한 약간 놀랍습니다.
$ echo influence | gawk --posix '{ print $1 + 0 }'
  -| inf
$ echo 0xDeadBeef | gawk --posix '{ print $1 + 0 }'
  -| 3735928559
  • 그렇지 않은 경우 --posix' gawk+inf', '-inf', '+nan' 및 '-nan' 4개의 문자열 값이 특별히 해석되어 해당 특수 값을 생성합니다. 선행 기호는 사용자(및 사용자)에게 값이 실제로 숫자라는 신호 역할을 합니다. 16진수 부동 소수점은 지원되지 않습니다(권장되지 않는 --non-decimal-data도 사용하지 않는 한). 예를 들어:
$ echo nanny | gawk '{ print $1 + 0 }'
  -| 0
$ echo +nan | gawk '{ print $1 + 0 }'
  -| +nan
$ echo 0xDeadBeef | gawk '{ print $1 + 0 }'
  -| 0

gawk네 가지 특수 값의 경우는 무시합니다. 따라서 "+nan"과 "+NaN"은 동일합니다.

입력을 처리하는 것 외에도 gawk값이 NaN 또는 무한대인 경우 출력에 "올바른" 값을 인쇄해야 합니다. 버전 4.2.2부터 이러한 값의 경우 gawk방금 설명한 네 가지 문자열("+inf", "-inf", "+nan" 또는 "-nan") 중 하나가 인쇄됩니다. 마찬가지로 POSIX 모드에서는 gawk시스템 C 함수의 결과가 값의 형식 문자열(무엇이든)을 사용하여 인쇄됩니다.printf()%g

관련 정보