awk에서 배열 요소 인쇄 문제

awk에서 배열 요소 인쇄 문제
p=n/1000
printf "%s",arr[p];

값을 확인했지만 아무것도 인쇄되지 않습니다 p.
꽤 잘 나왔습니다.
또한 다음과 같은 방법으로 요소를 인쇄해 보았습니다.

printf "%s",arr[7];

이것은 작동합니다.

답변1

에서 언급했듯이GNU Awk 사용자 가이드 8.2 숫자로 배열을 첨자화하기

배열에 대해 기억해야 할 중요한 점은 배열 첨자는 항상 문자열이라는 것입니다. 숫자 값이 아래 첨자로 사용되면 아래 첨자에 사용되기 전에 문자열 값으로 변환됩니다.

그렇다면 n7432입니다 . 기본적으로 반올림이 수행되지 않습니다 n/1000. 7.432그래서

$ awk -vn=7432 'BEGIN{arr[7] = "seven"; arr["7.432"] = "foo"; p = n/1000; print p, arr[p]}'
7.432 foo

하지만

$ awk -vn=7432 'BEGIN{arr[7] = "seven"; arr["7.432"] = "foo"; p = int(n/1000); print p, arr[p]}'
7 seven

답변2

보충@steeldriver의 훌륭한 답변.

7432/1000은 정수가 아닙니다. 부동 소수점 숫자는 awkC 컴파일러 double유형을 사용하여 내부적으로 표현됩니다. x86의 GNU 시스템에서는 IEEE 754 바이너리 64입니다.

1/3을 십진수로 표현할 수 없는 것처럼(즉, 0.33333에는 무수한 3이 있음) 7432/1000도 이진수로 표현할 수 없습니다. 이 숫자 awk의 대략적인 값 double은 이진수이며, 이를 십진수로 다시 변환하면 (정확히) 7.4320000000000003836930773104541003704071044921875입니다.

이제 awk정수가 아닌 값이 문자열 표현으로 변환되면 이진 내부 표현의 정확한 값이 완전히 보존되지 않습니다. 위의 숫자 대부분이 실제로 오류를 나타낸다는 점을 고려하면 이는 그다지 유용하지 않습니다. 대신, 다음과 같은 형식을 CONVFMT포함하는 printf특수 인수를 사용하여 부동 소수점을 다시 문자열로 변환하세요.

기본값 CONVFMT은 yes 입니다 %.6g. 이는 문자열로 변환할 때 소수점 이하 자릿수 6자리만 유지됨을 의미합니다. 이는 무엇이든 변경할 수 있지만 부동 소수점 지정자( %e, %f, %g...)만 이식 가능하다는 점에 유의하세요.

이러한 숫자는 문자열을 기대하는 함수나 연산자(예 substr(): 연결...) 에 대한 인수로 사용될 때 문자열로 변환됩니다.

@steeldriver가 말했듯이 그 중 하나는 항상 문자열인 연관 배열의 핵심입니다.

그래서 하는 것은 a[7432/1000] = x실제로 하는 것입니다 a[sprintf(CONVFMT, 7432/1000)]. 기본값을 사용하면 CONVFMT가 되고 , 또는 if 로 변경 a["0.7432"] = x하면 가 됩니다 .CONVFMT%.1ea["7.0e-01"] = x%.25ga["7.4320000000000003837"] = x

따라서 여기서 실제로 다음 CONVFMT=%.0f을 사용하여 배열의 키가 정수인지 확인할 수 있습니다.

$ awk -v CONVFMT=%.0f 'BEGIN{a[7432/1000] = 1; print a[7]}'
1

그러나 %.0f가장 가까운 정수로 반올림 하면 %d소수 부분도 잘립니다. and와 함께 사용할 수 있지만 CONVFMT=%d다음을 사용하여 이식할 수는 없습니다.gawkmawk

$ gawk -v CONVFMT=%d 'BEGIN{a[7564/1000] = 1; print a[7]}'
1
$ gawk -v CONVFMT=%.0f 'BEGIN{a[7564/1000] = 1; print a[8]}'
1

¹ 다음을 사용하여 print변환된 부동 소수점 인수는 제외됩니다.OFMT

관련 정보