セージ の メモ書き

メモこそ命の恩人だ

C# - 整数型(byte/short/int/long/nint)

整数 (Integer)

  • 整数とは、以下の総称である。
    • 正数(1, 2, 3, ...)、"自然数" とも呼ぶ。
    • 0
    • 負数(-1, -2, -3, ...)
  • "整" は、半端な数値でないことを意味する。
    • きりの良い数値。
    • 小数点以下がない数。


整数型(byte/short/int/long/nint)

docs.microsoft.com

型名 範囲 サイズ(byte) 符号
sbyte -128 ~ 127 1 あり
byte 0 ~ 255 1 なし
short -32,768 ~ 32,767 2 あり
ushort 0 ~ 65,535 2 なし
int -2,147,483,648 ~ 2,147,483,647 (約21億) 4 あり
uint 0 ~ 4,294,967,295 (約43億) 4 なし
long -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 (約922京) 8 あり
ulong 0 ~ 18,446,744,073,709,551,615 (約1845京) 8 なし
nint プラットフォームによって異なる 4 or 8 あり
nuint プラットフォームによって異なる 4 or 8 なし

試してみる。

Debug.WriteLine($"{sbyte.MinValue} ~ {sbyte.MaxValue}");
Debug.WriteLine($"size : {sizeof(sbyte)}, default : {default(sbyte)}");
// -128 ~ 127
// size : 1, default : 0

Debug.WriteLine($"{byte.MinValue} ~ {byte.MaxValue}");
Debug.WriteLine($"size : {sizeof(byte)}, default : {default(byte)}");
// 0 ~ 255
// size : 1, default : 0

Debug.WriteLine($"{short.MinValue} ~ {short.MaxValue}");
Debug.WriteLine($"size : {sizeof(short)}, default : {default(short)}");
// -32768 ~ 32767
// size : 2, default : 0

Debug.WriteLine($"{ushort.MinValue} ~ {ushort.MaxValue}");
Debug.WriteLine($"size : {sizeof(ushort)}, default : {default(ushort)}");
// 0 ~ 65535
// size : 2, default : 0

Debug.WriteLine($"{int.MinValue} ~ {int.MaxValue}");
Debug.WriteLine($"size : {sizeof(int)}, default : {default(int)}");
// -2147483648 ~ 2147483647
// size : 4, default : 0

Debug.WriteLine($"{uint.MinValue} ~ {uint.MaxValue}");
Debug.WriteLine($"size : {sizeof(uint)}, default : {default(uint)}");
// 0 ~ 4294967295
// size : 4, default : 0

Debug.WriteLine($"{long.MinValue} ~ {long.MaxValue}");
Debug.WriteLine($"size : {sizeof(long)}, default : {default(long)}");
// -9223372036854775808 ~ 9223372036854775807
// size : 8, default : 0

Debug.WriteLine($"{ulong.MinValue} ~ {ulong.MaxValue}");
Debug.WriteLine($"size : {sizeof(ulong)}, default : {default(ulong)}");
// 0 ~ 18446744073709551615
// size : 8, default : 0

Debug.WriteLine($"{nint.MinValue} ~ {nint.MaxValue}");
Debug.WriteLine($"default : {default(nint)}");
// -9223372036854775808 ~ 9223372036854775807
// default : 0
// long と同じ範囲であった。つまり、8バイト。
// ちなみに以下はビルドエラーとなる。nint の場合、実行時でなければサイズを取得できない。
// Debug.WriteLine($"size : {sizeof(nint)}"); 

Debug.WriteLine($"{nuint.MinValue} ~ {nuint.MaxValue}");
Debug.WriteLine($"default : {default(nuint)}");
// 0 ~ 18446744073709551615
// default : 0
// ulong と同じ範囲であった。
// 以下、nint と同様、ビルドエラーとなる。
// Debug.WriteLine($"size : {sizeof(nuint)}");


nint

docs.microsoft.com

  • native int
  • C# 9.0 以降で使用できる整数型。
  • 実行環境によりサイズが変化する。
    • 32ビット環境の場合、32ビットの整数。
    • 64ビット環境の場合、64ビットの整数。

プラットフォームターゲットの設定を x86 と x64 で切り替えて試してみる。

// --------------------
// x86 の場合
// --------------------

Debug.WriteLine($"Is64BitProcess : {Environment.Is64BitProcess}");
// Is64BitProcess: False

Debug.WriteLine($"{nint.MinValue} ~ {nint.MaxValue}");
// -2147483648 ~ 2147483647

Debug.WriteLine($"{nuint.MinValue} ~ {nuint.MaxValue}");
// 0 ~ 4294967295
// --------------------
// x64 の場合
// --------------------

Debug.WriteLine($"Is64BitProcess : {Environment.Is64BitProcess}");
// Is64BitProcess: True

Debug.WriteLine($"{nint.MinValue} ~ {nint.MaxValue}");
// -9223372036854775808 ~ 9223372036854775807

Debug.WriteLine($"{nuint.MinValue} ~ {nuint.MaxValue}");
// 0 ~ 18446744073709551615

// サイズが変わったことを確認。


実験

処理速度

  • 内容
    • ループ用の変数は、int が高速か?
    • byte/int/nint で試してみる。
    • byte の範囲が 0~255 で、ループ回すと、すぐオーバーフローする。
      なので、byte.MaxValue のループをネストする。int/nint も、それに合わせた処理にする。
  • 環境
    • Intel(R) Core(TM) i7-10700、メモリ16.0 GB
    • 64bitアプリ、.NET 6
  • 結果
    • int が最も高速であった。int > nint > byte の順。
    • nint がメモリのビット幅にマッチして高速かと予想したけど、int が最速だった。
    • int と byte 比較だと...
      • byte よりも int の方が約10%ほど高速。
      • 42億回ループ回して、1秒ほどの差がでた。
void Check(Action action)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();
    action();
    stopwatch.Stop(); ;
    Debug.WriteLine(stopwatch.Elapsed);
}
// byte
Check(new Action(() => 
{
    for (byte value1 = 0; value1 < byte.MaxValue; value1++)
        for (byte value2 = 0; value2 < byte.MaxValue; value2++)
            for (byte value3 = 0; value3 < byte.MaxValue; value3++)
                for (byte value4 = 0; value4 < byte.MaxValue; value4++)
                {
                    var dummy = value1;
                }
}));

// int
Check(new Action(() =>
{
    for (int value1 = 0; value1 < byte.MaxValue; value1++)
        for (int value2 = 0; value2 < byte.MaxValue; value2++)
            for (int value3 = 0; value3 < byte.MaxValue; value3++)
                for (int value4 = 0; value4 < byte.MaxValue; value4++)
                {
                    var dummy = value1;
                }
}));

// nint
Check(new Action(() =>
{
    for (nint value1 = 0; value1 < byte.MaxValue; value1++)
        for (nint value2 = 0; value2 < byte.MaxValue; value2++)
            for (nint value3 = 0; value3 < byte.MaxValue; value3++)
                for (nint value4 = 0; value4 < byte.MaxValue; value4++)
                {
                    var dummy = value1;
                }
}));

三重ループの場合の処理時間(ループ:約1600万回)

回数 byte int nint
1 00:00:00.0285998 00:00:00.0228462 00:00:00.0227176
2 00:00:00.0293150 00:00:00.0228459 00:00:00.0228818
3 00:00:00.0299042 00:00:00.0228578 00:00:00.0229551

四重ループの場合の処理時間(ループ:約42億回)

回数 byte int nint
1 00:00:06.2888814 00:00:05.6290908 00:00:05.7423374
2 00:00:06.2908128 00:00:05.6675731 00:00:05.7868968
3 00:00:06.2894321 00:00:05.6161856 00:00:05.7493328



以上