AWK가 printf를 사용하여 "0xffffffffbb6002e0"을 "ffffffffbb600000"으로 인쇄하는 이유는 무엇입니까?

AWK가 printf를 사용하여 "0xffffffffbb6002e0"을 "ffffffffbb600000"으로 인쇄하는 이유는 무엇입니까?

나는 AWK( ) gawk에서 16진수 숫자를 사용하려고 시도 했지만 때로는 printf아래 예와 같이 일부 LSB가 마스크 처리된 상태로 인쇄됩니다.

awk 'BEGIN { x=0xffffffffbb6002e0; printf("%x\n", x); }'
ffffffffbb600000

내가 왜 이렇게 행동하는 걸까요? 이 문제를 어떻게 바로잡을 수 있나요?

저는 gawk데비안 버스터 10을 사용하고 있습니다.

답변1

AWK의 숫자는 기본적으로 부동 소수점이며 값이 사용 가능한 정밀도를 초과합니다. 0xffffffffbb6002e0마지막으로 0 10000111110 1111111111111111111111111111111101110110110000000000IEEE-754 바이너리 64 형식으로 표현됩니다(배정밀도) 형식으로, 정수 값을 나타냅니다 0xffffffffbb600000. 0으로 반올림된 하위 12비트의 변경 사항을 확인하세요.

변환 후 반올림 오류가 발생하는 가장 작은 양의 정수 double는 2 53 + 1입니다. 숫자가 클수록 doublea가 나타낼 수 있는 값 사이의 간격이 커집니다. (단계는 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에서 문자열을 숫자처럼 보이도록 변환하려면 다음을 수행하세요.

  1. 프로그램 상수로 변수에 할당할 수 있습니다.
  2. 이 기능은 strtonum()텍스트를 변환할 수 있습니다.
  3. 이 옵션을 사용하여 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필요에 따라 변수를 PREC53보다 크게 만들어야 합니다.

$ 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

관련 정보