AWKの整数値の移植可能範囲は何ですか?

AWKの整数値の移植可能範囲は何ですか?

39ページのセクション3.2.9に従うコンパチブル・シルスクリーフティング区(第5版)、互換性のあるシェルスクリプトを作成する方法については、限られた整数範囲を持ついくつかのAWK実装があります(私の翻訳)。

たとえば、AWKに次の出力が表示されませんか?

$ awk 'BEGIN{print 2147483648}'
2.14748e+09
$

これは、0x7FFFFFFF(4バイト符号付き整数の最大値)以上の整数を処理できない実装です。これが、数桁の整数を扱うときに注意しなければならない理由です。計算せずに表示したい場合は、文字列として扱う必要があります。

しかし、ポータブルスコープが正確に何であるかを本で見たことはありません。それで、POSIXのドキュメントをチェックして見つけました。SUSv2範囲が指定されていないようです。次のように言います。

値が大きすぎるか小さすぎて表現できない場合、動作は定義されません。

存在する2004年版、それ〜らしい整数および浮動小数点値はそれぞれ long および double 型で符号が付けられます ("..." はその部分を省略したことを意味します)。

整数変数と定数は、ISO C標準の符号付き長いデータ型と同じように実装する必要があります。浮動小数点はISO C標準二重タイプと同じように実装する必要があります。

これは[-2147483647、+2147483647](PS. Wikipediaで範囲を見つけました)が浮動小数点として扱われない移植可能な整数範囲であることを意味しますか?

ベストアンサー1

数値を浮動小数点数ではなく整数として扱うことが正確に何を意味するのか疑問に思います。

出力される内容を意味するなら、printf "%d"gawk、mawk、およびBusyboxでは-2147483647が安全なように見えます。下の数字はmawkで-2147483647、Busyboxで-2147483648として印刷されますが、gawkと私のMacのawkが何であれ実際の値を印刷します。

一方、数字を使用して計算を実行すると、より広い範囲が得られます。 awkは何でも使うべきです「ISO C規格ダブルタイプ」プラットフォームにあります。最も一般的なのはIEEE 754倍精度浮動小数点ですが、必須ではありません。

IEEE doubleの場合、歌手は52 + 1ビットなので、約±2 53の範囲のすべての整数を正確に表現できるはずです。数字を印刷するのは出力形式の問題です。

print()のデフォルトの出力形式OFMTはです%.6g。これは、有効数字の6桁を印刷することを意味します。しかし、これがすべて真実ではないので整数は整数で印刷する必要があります。しかし、awkのバージョンに応じて、ここでは整数として計算されます。一部では、次の特定の数値範囲に制限します。

$ busybox awk 'BEGIN { a = 9007199254740992; print a; printf OFMT "\n", a }'
9007199254740992
9.0072e+15

公共の。

$ mawk 'BEGIN { a = 9007199254740992; 
                print a; printf OFMT "\n", a }'
9.0072e+15
9.0072e+15

OFMTとにかく、たとえば、%.0fmawkで数字全体を印刷するように変更することもできます。

$ mawk 'BEGIN { OFMT="%.0f"; a = 9007199254740992;
                print a; printf OFMT "\n", a }'
9007199254740992
9007199254740992

±2 53を超えると、最も低いビットが落ち始め、問題が発生します。

$ awk 'BEGIN { OFMT="%.0f"; a=9007199254740990; 
               for (i = 0; i < 6; i++) print a, "+", i, "=", a + i; }'
9007199254740990 + 0 = 9007199254740990
9007199254740990 + 1 = 9007199254740991
9007199254740990 + 2 = 9007199254740992
9007199254740990 + 3 = 9007199254740992
9007199254740990 + 4 = 9007199254740994
9007199254740990 + 5 = 9007199254740996

もちろん、計算は関係なく浮動小数点数を使用して実行されるため、intで切り捨てられない限り、ここではをOFMT取得します。2000000 = 3 * 666666.6666661999998 = 3 * 666666

$ awk 'BEGIN{a = 2000000; b = a/3; print 3*b}'
2000000
$ awk 'BEGIN{a = 2000000; b = int(a/3); print 3*b}'
1999998

使用しているawkの目的の動作を確認するには、テストスクリプトを作成する必要があります。

おすすめ記事