私はAWK()gawk
で16進数を使用しようとしましたが、時にはprintf
以下の例のように一部のLSBがマスクされて印刷されます。
awk 'BEGIN { x=0xffffffffbb6002e0; printf("%x\n", x); }'
ffffffffbb600000
私はなぜこのように振る舞うのでしょうか?この問題をどのように修正できますか?
私はgawk
Debianバスター10を使用しています。
答え1
AWK の数値はデフォルトで浮動小数点であり、値が使用可能な精度を超えています。0xffffffffbb6002e0
最後に、0 10000111110 1111111111111111111111111111111101110110110000000000
IEEE-754バイナリ64形式で表現されます(倍精度)形式で、整数値を表します0xffffffffbb600000
。ゼロに丸められた下位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進数)を処理します。GAWKstrtonum
機能。
答え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
単語のように見えるため拒否します。他の2つのケースではうまくいきます。
したがって、awkで作業を簡素化するには、10進数を使用する必要があります。 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