일반 관계 연산자 '<'가 awk에서 예상대로 작동하지 않습니다.

일반 관계 연산자 '<'가 awk에서 예상대로 작동하지 않습니다.

다음과 같은 파일이 있습니다.

0.2
0.2
0.2
0.2
0.2
0.2
0.2024
0.2025
0.2027
0.2027
0.2029
0.2059
0.2059
0.2059
0.2059
0.2099
0.2099
0.2099
0.2105
0.2113
0.2113
0.2195
0.2198
0.2206
0.2206
0.2206
0.2989
0.2989
0.2989
0.3
0.3

범위에 포함된 값의 개수를 계산하고 싶습니다. 예를 들면 다음과 같습니다.

0.2 18
0.21 5
0.22 3
0.23 0
0.24 0
0.25 0
0.26 0
0.27 0
0.28 0
0.29 3
0.3 2

보시다시피 제가 사용한 간격은 0.01입니다. 이를 구현하는 데 사용하고 있지만 awk이상한 동작이 발생합니다.

awk 'BEGIN {for (i=0;i<1.01;i+=0.01) a[i]=0} {
    for (j=0;j<=1;j+=0.01) 
      if($1>=j && $1<j+0.01) {
        a[j]+=1
      }
    } 
    END {for (k=0;k<1.01;k+=0.01) print k,a[k]}' test_OH.txt

결과:

0.19 6
0.2 12
0.21 5
0.22 3
0.23 0
0.24 0
0.25 0
0.26 0
0.27 0
0.28 0
0.29 5
0.3 0

누구든지 나를 도와줄 수 있나요? 물론 아무것도 고려하지 않았기 <때문에 예상대로 작동하지 않는 것 같습니다 . $1 == j+0.01감사합니다!

답변1

awk -v s=0.2 -v e=0.3 -v d=0.01 '
   BEGIN { m = 1/d }
   { a[int($1*m)]++ }
   END{ e *= m; for(s = int(s*m); s <= e; s++) print s*d, a[s]+0 }
' test_OH.txt

0.2 18
0.21 5
0.22 3
0.23 0
0.24 0
0.25 0
0.26 0
0.27 0
0.28 0
0.29 3
0.3 2

(시작 s) e(끝) 및 d(증분/단계) 변수는 필요에 따라 조정할 수 있습니다.


  1. 반복된 덧셈으로 범위를 생성하는 것은 0.01부동 소수점 숫자가 할 수 없는 일을 보여주는 거의 교과서적인 예입니다. 왜냐하면 부동 소수점 숫자는 0.012진법으로 정확하게 표현할 수 없고 덧셈을 할 때마다 오류가 누적되기 때문입니다.

  2. 각 라인의 전체 범위를 스캔하는 것은 비효율적이고 의미가 없습니다.

  3. ""awk의 변수는 또는 로 초기화될 필요가 없습니다 0.

답변2

이 시도:

awk '
  BEGIN {for (i=0;i<1.01;i+=0.01) a[i]=0}
  {
    n = int($1 * 100) / 100
    a[n] += 1
  }
  END {for (k=0;k<1.01;k+=0.01) print k,a[k]}'

또는 이해하기 쉽지 않은 이 내용은 다음과 같습니다.

awk 'BEGIN {for (i=0;i<1.01;i+=0.01) a[i]=0} {
    for (j=0;j<=1;j+=0.01)
      if(("X" $1 >= "X" j) && ("X" $1 < "X" j+0.01)) {
        a[j]+=1
      }
    }
    END {for (k=0;k<1.01;k+=0.01) print k,a[k]}'

원본이 작동하지 않는 이유는 위의 Quasimodo의 설명을 참조하세요.

답변3

이것을 답변으로 게시해야 할지 댓글로 게시해야 할지 잘 모르겠지만, 다음은 내 컴퓨터에서 이 경우의 부정확성과 결과 숫자에 대한 간단한 데모입니다.

$ awk 'BEGIN { d = 0.01; printf "%.20f\n", d; for (i = 0; i < 30; i++) a += d; printf "%.20f\n%.20f\n", 0.3, a }'   
0.01000000000000000021
0.29999999999999998890
0.30000000000000009992

첫 번째 숫자는 실제 저장된 숫자인 0.01입니다. 1/100은 1/5의 요소를 포함하고 이진수로 표현할 수 없기 때문에 정확하지 않습니다.

두 번째는 0.3에 저장된 내용이고, 세 번째는 0.01에 자신을 30번 더한 값입니다. ( 0.01 * 30모든 단계에서 중간 반올림이 있기 때문에 동일하지도 않은 것 같습니다 .)

다른 답변에는 해결책이 있습니다. 좋아요를 눌러주세요.

관련 정보