テスト限界:

テスト限界:

これは探求的な質問です。つまり、この質問が何についてのものか完全にはわかりませんが、Bashの最大整数に関連していると思います。とにかく明確に定義します。

$ echo $((1<<8))
256

少し動いて整数を生成します。どのくらい離れて行けますか?

$ echo $((1<<80000))
1

明らかに、私たちはまだこの点に達していません。 (1は予期せぬことでした。もう一度説明します。) しかし、

$ echo $((1<<1022))
4611686018427387904

それでも肯定的です。しかしこれはない:

$ echo $((1<<1023))
-9223372036854775808

そしてさらに、

$ echo $((1<<1024))
1

なぜ1ですか?なぜ次のような状況が発生しますか?

$ echo $((1<<1025))
2
$ echo $((1<<1026))
4

このシリーズを分析したい人はいますか?

修正する

マイコンピュータ:

$ uname -a
Linux tomas-Latitude-E4200 4.4.0-47-generic #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

答え1

吹く変数を使用したintmax_t算術演算の実行。お使いのシステムでは、長さは64ビットなので、次のようになります。

$ echo $((1<<62))
4611686018427387904

これは

100000000000000000000000000000000000000000000000000000000000000

バイナリ形式(1の後に62個のゼロがオーム)。戻る:

$ echo $((1<<63))
-9223372036854775808

これは

1000000000000000000000000000000000000000000000000000000000000000

2進数(0 63個)、2の補数算術。

表現可能な最大の整数を得るには、1 を減算します。

$ echo $(((1<<63)-1))
9223372036854775807

これは

111111111111111111111111111111111111111111111111111111111111111

バイナリの形で。

指摘したとおりイルカチョ~の回答、オフセットモジュロ64を使用して64ビットに移動x86CPU(使用するかどうかにかかわらずRCLSHLは、次のように表示される動作を説明します。

$ echo $((1<<64))
1

と同じです$((1<<0))$((1<<1025))$((1<<1))$((1<<1026))$((1<<2))

タイプ定義と最大値は以下で確認できます。stdint.h;システムから:

/* Largest integral types.  */
#if __WORDSIZE == 64
typedef long int                intmax_t;
typedef unsigned long int       uintmax_t;
#else
__extension__
typedef long long int           intmax_t;
__extension__
typedef unsigned long long int  uintmax_t;
#endif

/* Minimum for largest signed integral type.  */
# define INTMAX_MIN             (-__INT64_C(9223372036854775807)-1)
/* Maximum for largest signed integral type.  */
# define INTMAX_MAX             (__INT64_C(9223372036854775807))

答え2

2.05bのCHANGESドキュメントbash

ジェイ。シェルは、longの代わりにシステムがサポートする最大整数サイズ(intmax_t)を使用して算術を実行します。

x86_64システムのintmax_t符号付き64ビット整数に対応します。これにより、-2^63との間の意味のある値が得られます2^63-1。その範囲を超えるとサラウンドを得ることができます。

答え3

1024を移動すると、移動量は実際にはビット数(64)のモジュロであるため、1に1024 === 64 === 0なります1025 === 65 === 1

a以外の値を移動すると、1これがビット回転ではないことが明らかになります。なぜなら、移動値が(少なくとも)64になるまで、高いビットが低いビットに循環しないからである。

$ printf "%x\n" $(( 5 << 63 )) $(( 5 << 64 ))
8000000000000000
5

この動作はシステムによって異なる場合があります。これbashコードStephenがリンクされています右の値を確認せずに単純なシフトのみが表示されます。私の記憶が正しい場合、x86プロセッサはシフト値の下位6ビット(64ビットモード)のみを使用するため、この動作は機械語で直接表示される可能性があります。また、Cではビット幅を超えた移動が明確に定義されていないと思います(gccこの点について警告)。

答え4

移動して整数を生成します。どのくらい離れて行けますか?

最大整数はラップを表します(ほとんどのシェルではデフォルト)。
64ビット整数は通常2**63 - 1
それ0x7fffffffffffffffでなければ922337203685477580712月です。

数字「+1」は負の数になります。

これはと同じです1<<63

$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1

その後、プロセスが再び繰り返される。

$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))

結果はmod 64移動値[a]によって異なります。

[1] 送信者:インテル®64およびIA-32アーキテクチャーソフトウェア開発者ハンドブック:ボリューム2カウントは5ビット(または64ビットモードでREX.Wを使用している場合は6ビット)でマスクされます。カウント範囲は0〜31(または64ビットモードを使用し、REX.Wを使用している場合は63)に制限されます。

また:$((1<<0))それであることを覚えなさい1

$ for i in 80000 1022 1023 1024 1025 1026; do echo "$((i%64)) $((1<<i))"; done
 0 1
62 4611686018427387904
63 -9223372036854775808
 0 1
 1 2
 2 4

したがって、それはすべて数字が64の倍数にどれだけ近いかによって異なります。

テスト限界:

最大の正(および負の)整数をテストする信頼できる方法は、各ビットを順番にテストすることです。とにかく、ほとんどのコンピュータでは64ステップ未満で、遅すぎることはありません。

強く打つ

まず、フォーマットの最大の整数が必要です2^n(1ビットの後にゼロが続くセット)。左に移動してこれを行うことができます。Shiftを使用すると、数字は負になります(「改行」とも呼ばれます)。

a=1;   while ((a>0));  do ((b=a,a<<=1))  ; done

結果は次のとおりですb。ループが失敗した最後のシフトの前の値。

次に、各ビットを試して、どちらが符号に影響を与えるかを調べる必要がありますe

c=$b;d=$b;
while ((c>>=1)); do
      ((e=d+c))
      (( e>0 )) && ((d=e))
done;
intmax=$d

最大の整数(intmax)はの最後の値から派生しますd

否定的な側面(より小さい0)では、すべてのテストを繰り返しますが、ビットをラップせずに0に設定できるときにテストします。

すべてのステップを印刷する完全なテストは次のとおりです(bashの場合)。

#!/bin/bash
sayit(){ printf '%020d 0x%016x\n' "$1"{,}; }
a=1;       while ((a>0)) ; do((b=a,a<<=1))              ; sayit "$a"; done
c=$b;d=$b; while((c>>=1)); do((e=d+c));((e>0))&&((d=e)) ; sayit "$d"; done;
intmax=$d
a=-1;      while ((a<0)) ; do((b=a,a<<=1))              ; sayit "$b"; done;
c=$b;d=$b; while ((c<-1)); do((c>>=1,e=d+c));((e<0))&&((d=e)); sayit "$d"; done
intmin=$d       

printf '%20d max positive value 0x%016x\n' "$intmax" "$intmax"
printf '%20d min negative value 0x%016x\n' "$intmin" "$intmin"

シェン

ほとんどすべてのシェルに変換されます。

#!/bin/sh
printing=false
sayit(){ "$printing" && printf '%020d 0x%016x\n' "$1" "$1"; }
a=1;       while [ "$a" -gt 0  ];do b=$a;a=$((a<<1)); sayit "$a"; done
c=$b;d=$b; while c=$((c>>1)); [ "$c" -gt 0 ];do e=$((d+c)); [ "$e" -gt 0 ] && d=$e ; sayit "$d"; done;
intmax=$d
a=-1;      while [ "$a" -lt 0  ];do b=$a;a=$((a<<1)); sayit "$b"; done;
c=$b;d=$b; while [ "$c" -lt -1 ];do c=$((c>>1));e=$((d+c));[ "$e" -lt 0 ] && d=$e ; sayit "$d"; done
intmin=$d       

printf '%20d max positive value 0x%016x\n' "$intmax" "$intmax"
printf '%20d min negative value 0x%016x\n' "$intmin" "$intmin"

多くのシェルに対して上記のコマンドを実行すると、すべて(bash 2.04およびmkshを除く)はこのシステムで
最大()値を受け入れます。2**63 -1

興味深いことに、レポートは次のように述べています。attシェル:

$ attsh --version
version         sh (AT&T Research) 93u+ 2012-08-01

ただし、エラーはkshではなくksh値に印刷されます$((2^63))

関連情報