AWKがprintfを使って「0xffffffffbb6002e0」を「ffffffffbbbb600000」として印刷するのはなぜですか?

AWKがprintfを使って「0xffffffffbb6002e0」を「ffffffffbbbb600000」として印刷するのはなぜですか?

私はAWK()gawkで16進数を使用しようとしましたが、時にはprintf以下の例のように一部のLSBがマスクされて印刷されます。

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

私はなぜこのように振る舞うのでしょうか?この問題をどのように修正できますか?

私はgawkDebianバスター10を使用しています。

ベストアンサー1

AWK の数値はデフォルトで浮動小数点であり、値が使用可能な精度を超えています。0xffffffffbb6002e0最後に、0 10000111110 1111111111111111111111111111111101110110110000000000IEEE-754バイナリ64形式で表現されます(倍精度)形式で、整数値を表します0xffffffffbb600000。ゼロに丸められた下位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進数)を処理します。GAWKstrtonum機能

おすすめ記事