나는 AWK( ) gawk
에서 16진수 숫자를 사용하려고 시도 했지만 때로는 printf
아래 예와 같이 일부 LSB가 마스크 처리된 상태로 인쇄됩니다.
awk 'BEGIN { x=0xffffffffbb6002e0; printf("%x\n", x); }'
ffffffffbb600000
내가 왜 이렇게 행동하는 걸까요? 이 문제를 어떻게 바로잡을 수 있나요?
저는 gawk
데비안 버스터 10을 사용하고 있습니다.
답변1
AWK의 숫자는 기본적으로 부동 소수점이며 값이 사용 가능한 정밀도를 초과합니다. 0xffffffffbb6002e0
마지막으로 0 10000111110 1111111111111111111111111111111101110110110000000000
IEEE-754 바이너리 64 형식으로 표현됩니다(배정밀도) 형식으로, 정수 값을 나타냅니다 0xffffffffbb600000
. 0으로 반올림된 하위 12비트의 변경 사항을 확인하세요.
변환 후 반올림 오류가 발생하는 가장 작은 양의 정수 double
는 2 53 + 1입니다. 숫자가 클수록 double
a가 나타낼 수 있는 값 사이의 간격이 커집니다. (단계는 2, 4, 8 등입니다. 따라서 숫자의 하위 16진수는 0으로 반올림됩니다.)
GAWK를 사용하여 MPFR 및 MP(Debian의 경우)로 빌드된 경우 강제로임의의 정밀도대신 다음 -M
옵션을 사용하십시오.
$ awk -M 'BEGIN { x=0xffffffffbb6002e0; printf("%x\n", x); }'
ffffffffbb6002e0
계산의 경우 기본값은 IEEE-754 배정밀도와 동일한 53비트 정밀도이지만 PREC
변수를 사용하여 이를 제어할 수 있습니다. 자세한 내용은 위에 링크된 매뉴얼을 참조하세요.
기본 정밀도보다 더 많은 정밀도가 필요한 큰 정수 및 부동 소수점 값을 처리하는 데 차이가 있어 놀라운 동작이 발생할 수 있습니다. 큰 정수는 -M
기본 설정을 사용하여 올바르게 구문 분석되는 반면(후속 계산에만 영향을 받음 PREC
) 부동 소수점 값은 구문 분석 시 정의된 정밀도로 저장됩니다. 즉, PREC
사전에 적절한 설정을 지정해야 합니다.
# Default settings, integer value too large to be exactly represented by a binary64
$ awk 'BEGIN { v=1234567890123456789; printf "%.20f\n", v }'
1234567890123456768.00000000000000000000
# Forced arbitrary precision, same integer value stored exactly without rounding
$ awk -M 'BEGIN { v=1234567890123456789; printf "%.20f\n", v }'
1234567890123456789.00000000000000000000
# Default settings, floating-point value requiring too much precision
$ awk 'BEGIN { v=123456789.0123456789; printf "%.20f\n", v }'
123456789.01234567165374755859
# Forced arbitrary precision, floating-point parsing doesn’t change
$ awk -M 'BEGIN { v=123456789.0123456789; printf "%.20f\n", v }'
123456789.01234567165374755859
# Forced arbitrary precision, PREC set in the BEGIN block, no difference
$ awk -M 'BEGIN { PREC=94; v=123456789.0123456789; printf "%.20f\n", v }'
123456789.01234567165374755859
# Forced arbitrary precision, PREC set initially
$ awk -M -vPREC=94 'BEGIN { v=123456789.0123456789; printf "%.20f\n", v }'
123456789.01234567890000000000
입력 값을 읽을 때 AWK는 10진수 값만 숫자로 인식하여 10진수가 아닌 값(8진수 또는 16진수)을 처리합니다.GAWK strtonum
기능.
답변2
awk에서 문자열을 숫자처럼 보이도록 변환하려면 다음을 수행하세요.
- 프로그램 상수로 변수에 할당할 수 있습니다.
- 이 기능은
strtonum()
텍스트를 변환할 수 있습니다. - 이 옵션을 사용하여 awk(현재는 더 이상 사용되지 않음)를 호출할 수 있습니다
-n
.
숫자로 변환되면 대부분의 awk(gawk, mawk, nawk, bawk)에서는 64비트 부동 소수점 숫자로 저장됩니다. 이 숫자에는 53개의 가수만 포함될 수 있습니다. 추가 비트는 잘립니다. 이는 53/4 = 13개의 16진수 숫자를 허용합니다(기술적으로 1은 정수이고 점 뒤에 13개의 숫자가 있습니다).
사용하는 16진수는 0xffffffffbb6002e0
바이너리입니다.
bc <<<"obase=2;ibase=16;FFFFFFFFBB6002E0"
1111111111111111111111111111111110111011011000000000001011100000
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<== up to here 53 bits.
awk의 모든 소수와 대부분의 정수는 부동 소수점 숫자로 저장됩니다. GNU awk의 유일한 다른 옵션은 임의 정밀도를 사용하는 것입니다 -M
. 이 옵션을 사용하면 모든 정수가 필요에 따라 컴퓨터 메모리가 허용하는 만큼 즉시 표현됩니다.
$ awk -M 'BEGIN{print 3^4^5}'
373391848741020043532959754184866588225409776783734007750636931722079040617265251229993688938803977220468765065431475158108727054592160858581351336982809187314191748594262580938807019951956404285571818041046681288797402925517668012340617298396574731619152386723046235125934896058590588284654793540505936202376547807442730582144527058988756251452817793413352141920744623027518729185432862375737063985485319476416926263819972887006907013899256524297198527698749274196276811060702333710356481
이렇게 하면 정수가 다른 정수와의 계산에만 사용되는 한 문제 없이 정수를 사용할 수 있습니다. 분열이 없습니다.
$ awk -M 'BEGIN{x=strtonum(0xffffffffbb6002e0); y=x+234; z=x/77; printf("%x\n%x\n%f\n",x,y,z)}'
ffffffffbb6002e0
ffffffffbb6003ca
239568104838418400.000000
올바른 결과는 bc에 따라야 x/77
합니다 239568104838418388.36363636363636363636
.
53자리 이상이 필요한 소수 부분이 있는 숫자가 필요한 경우(이는 정밀도 보존을 사용하는 경우에도 ) -M
필요에 따라 변수를 PREC
53보다 크게 만들어야 합니다.
$ awk -M -vPREC=200 'BEGIN{x=strtonum(0xffffffffbb6002e0); y=x+234; z=x/77; printf("%x\n%x\n%f\n",x,y,z)}'
ffffffffbb6002e0
ffffffffbb6003ca
239568104838418388.363636
도움이 되었기를 바랍니다.
모든 청구에 대한 코드:
이식성을 위해 셸을 사용하고 %a
부동 소수점 숫자의 내부 표현에 더 가까운 것을 사용하려면 53비트가 13비트 숫자입니다.
$ dash -c 'printf "%a\n" 0x1.12345678901234567890123'
0x1.1234567890123p+0
다른 쉘(및 일부 awks)은 80비트 숫자와 64비트 가수, 최대 16비트 숫자를 사용할 수 있습니다.
ksh -c 'printf "%a\n" 0x1.12345678901234567890123'
0x1.1234567890123456000000000000p+0
awk는 허용할 수 있는 16진수로 제한됩니다(프로그램 상수( x=
)).
$ awk 'BEGIN { x=0x1fffffffffffff ; y=0x3fffffffffffff; printf("%18s %16x\n%18s %16x\n", x, x+0,y,y+0); }'
9007199254740991 1fffffffffffff
18014398509481984 40000000000000
$ mawk -vx=$(printf '%d\n' 0xffffffff) 'BEGIN{y=x*2;printf("%18s %16x\n%18s %16x\n", x, x+0,y,y+0); }'
4294967295 7fffffff
8.58993e+09 7fffffff
$ bawk 'BEGIN { x=2147483647 ; y=x*2+1; printf("%18s %16x\n%18s %16x\n", x, x+0,y,y+0); }'
2147483647 7fffffff
4294967295 80000000
또한 파일 및/또는 사용자의 입력에는 옵션 -n
(더 이상 사용되지 않음strtonum()
) 또는 기능을 사용하십시오(권장).
$ awk '{x=$1; printf "%s %x\n",x,x}' <<<0x123
0x123 0
$ awk -n '{x=$1; printf "%s %x\n",x,x}' <<<0x123
0x123 123
$ awk -n '{x=strtonum($1); printf "%s %x\n",$1,x}' <<<0x123
0x123 123
첫 번째 입력에서 awk는 첫 번째 입력만 읽고 0
그 이후의 모든 항목은 x
단어처럼 보이기 때문에 거부합니다. 다른 두 경우에는 잘 작동합니다.
따라서 awk로 작업을 단순화하려면 십진수를 사용해야 합니다. printf가 제한되어 있으면 bc를 사용하십시오.
$ val=$(printf "%d" 0x1234567890)
$ awk -vx="$val" 'BEGIN{printf "%s %x\n", x,x}'
78187493520 1234567890
$ val=$(bc <<<'ibase=16;1234567890')
$ awk -vx="$val" 'BEGIN{printf "%s %x\n", x,x}'
78187493520 1234567890
하지만 awk에는 여전히 한계가 있습니다.
$ val=$(bc <<<'ibase=16; 12345678901234')
$ awk -vx="$val" 'BEGIN{printf "%s %x\n", x,x}'
5124095575331380 12345678901234
$ val=$(bc <<<'ibase=16; 123456789012345')
$ awk -vx="$val" 'BEGIN{printf "%s %x\n", x,x}'
81985529205302085 123456789012340
5
여기서는 53비트 부동 소수점 숫자로 표현할 수 없기 때문에 마지막 것을 잘라냅니다 .
임의 정밀도 bignum
( ) 옵션을 사용하면 큰 숫자를 처리하는 기능이 향상되지만 정수에만 해당됩니다.-M
$ val=$(bc <<<'ibase=16; 12345678901234567890123456789')"
$ awk -vx="$val" 'BEGIN{printf "%s %x\n", x,x}'
5907679980460342222050878921467785 5.90768e+33
$ awk -M -vx="$val" 'BEGIN{printf "%s %x\n", x,x}'
5907679980460342222050878921467785 12345678901234567890123456789
정말로 큰 숫자와 긴 소수점 이하 자릿수를 처리해야 한다면 다음이 필요합니다.반품사용된 PREC를 변경합니다(기본값은 53).
$ awk -M -vx='12345678901234567890123456789' 'BEGIN{printf "%s \n%f\n", x,x/100}'
12345678901234567890123456789
123456789012345678152597504.000000
$ awk -M -vPREC=500 -vx='12345678901234567890123456789' 'BEGIN{printf "%s \n%f\n", x,x/100}'
12345678901234567890123456789
123456789012345678901234567.890000
답변3
gawk, mawk134 및 mawk2의 다양한 정밀도 수준을 처리하는 방법은 서브쉘 gawk 실행을 캡슐화하는 래퍼 함수를 작성하는 것입니다. 따라서 함수가 현재 환경의 정밀도보다 높은 입력을 감지할 때마다 이 래퍼를 통해 자신을 호출하여 gawk -M
하위 쉘에서 실행되고 getline을 사용하여 결과를 반환합니다(래퍼에 의해 캡슐화되어 마지막 후행\ N).
내가 소인수분해를 하고 싶다면 말해보세요 2^190 - 1
. 나는 그것들을 인용하고 내 함수에 문자열로 전달하므로, 정확한 사전 트리밍을 수행하는 대신 하위 쉘이 모든 것을 계속 볼 수 있으므로 하위 쉘의 요점이 무효화됩니다.
래퍼의 일부로 서브셸에 대해 선언해야 하는 PREC에서 최선의 추측을 한 다음 확실하게 고정된 패딩을 추가합니다.
답변4
@user232326: mawk
그렇군요아니요다른 것보다 숫자가 적거나 정밀도가 낮습니다.non-bignum
awk
echo '0x1' | mawk '{ __ = (_+=_^=_<_)^_^_+_
_ = $___
do { print _
_ = (_) "F" } while(--__) }' |
mawk '$++NF = +$_' CONVFMT='%.f'
0x1 1
0x1F 31
0x1FF 511
0x1FFF 8191
0x1FFFF 131071
0x1FFFFF 2097151
0x1FFFFFF 33554431
0x1FFFFFFF 536870911
0x1FFFFFFFF 8589934591
0x1FFFFFFFFF 137438953471
0x1FFFFFFFFFF 2199023255551
0x1FFFFFFFFFFF 35184372088831
0x1FFFFFFFFFFFF 562949953421311
0x1FFFFFFFFFFFFF 9007199254740991 <—- same 53-bit cutoff as everyone else
0x1FFFFFFFFFFFFFF 144115188075855872
0x1FFFFFFFFFFFFFFF 2305843009213693952
0x1FFFFFFFFFFFFFFFF 36893488147419103232
0x1FFFFFFFFFFFFFFFFF 590295810358705651712
그에 관해서는 gawk w/ GMP
동일한 구문이 똑같이 잘 작동합니다.
gawk -nMb '$++NF = +$_' gawk -nMb '$_+=_' # bare-minimum for decoding only
0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FF
4039625758913875912589359586083743995055512833714435504016293178
4405818923584863616496501764403641829610897451152372524367649448
9381136513688601904830603539007885967091262451146877471879870651
3349507204798008446034599027330327469520229761792309521308822705
7315045381303609469864426332260759440498904912981902392916737085
4280258562184832057118685702200441579025725972570741637827408855
7539268782324108022139590742950464807732169699793894037705738050
4622016541609039033907105888525262156446377158664154337098178225
8208724188074965854412482977694064579867966694295026692915370058
0664809825619018524194481701382449528831
0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FF
1363435169524269911828730305917228578060330202495290865539790982
7371516648113991190203302931565024840299466147451962815913873385
2522148007951372470634694349884863287355274123692326228153506025
6449621064516989547745964858178261655700151613192377357876272375
3156697498965000125995000331697960011316222573511904381270377443
4456738875664045570001855928254411693905730491114844096087034918
0110069521894617937431758347281426018625770132400320548130722516
6581169572950590530092280535153064143971968989561240329571796530
4034671009378453485380650812724095212618212396062157234960481467
1312496126201400644568812644451589364365644177632186208286933790
9829018821635355377770812129054951732940645330118952100067845292
9499538615211430772648425799413833175610717429354109678520925936
9213741889835945449962987646277279520936823276212321257829515103
3833942601963332189216012837778886594561378459489506510978807905
1381170571094365120915372807398095428422973784056054752315872220
6176340894514475543363534324174989951767803426763248896782575695
6047046953931595142033232854792107764474920475260981720944316709
8739461779304244458289383760901691933781958789000516340686979313
5446799567286170096351223188223641209884190975068669526951363494
8064661926449661593498469096732000102551481986625059721859097023
1726688811730072732699831526450745038544550742727648714254733590
7774351873409504567020373570218528016291856798481655030939274271
4787653513477621616294217160057179651190358795284704549316135872
5782302794393563446379952423431203733351023596207851972269134924
1473866429560425952173227274453753743028488443693826611022885537
5995608665402239484573975444565201963942537401503451945098413849
2184683355191045373463587431269003903982824275385711729868082132
6682795880292533526378698693688996358845682733278495368170564525
9456366887736325297172769244159702608462232371649579128861166308
3146179523134793830196042118066256429686413912354295908154824425
6130341819910904936906533980771755459818443263092971274710031970
7573512975965883846474277774713629817982323051193651451248156736
2996831962992996635761366324620420095941245617301824773213245469
3201871694784767029791611132886255360021651781010829953339166910
0115409479385913245176484047267776268252482696842335688711201114
8647555167444815602858442639151579849209445956292545371253991252
9247285581648184047805290035018987112075523528720001019297013315
3178377044945635942923139339040177840832567544772268363635082205
8618823457749648313208184464474111