3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

C#の基本的な数値型同士の計算って何型になるんだっけ?

Last updated at Posted at 2022-11-03
  • intとlongで計算したら結果はlongになる
  • intとdoubleで計算したら結果はdoubleになる

なんて話をよく聞くと思いますが、数値でも沢山の型があるC#というか.NETというかでどれとどれを計算したらどれになるんだっけ?っていうメモです。

計算

sbyte sbyteL = 0, sbyteR = 0;
byte byteL = 0, byteR = 0;
...
char charL = '0', charR = '0';

Console.WriteLine("sbyte + sbyte -> {0}", (sbyteL + sbyteR).GetType());
Console.WriteLine("sbyte + byte -> {0}", (sbyteL + byteR).GetType());
...
Console.WriteLine("char + char -> {0}", (charL + charR).GetType());

みたいな感じでやった結果が以下の通り。
Visual Studio 2022.NET 6.0でやって明らかに数値じゃない型とか小文字のエイリアスがない型は除外しています。

サイズ、符号有無順

左\右 sbyte byte short ushort char int uint long ulong float double decimal
sbyte int int int int int int long long CS0034 float double decimal
byte int int int int int int uint long ulong float double decimal
short int int int int int int long long CS0034 float double decimal
ushort int int int int int int uint long ulong float double decimal
char int int int int int int uint long ulong float double decimal
int int int int int int int long long CS0034 float double decimal
uint long uint long uint uint long uint long ulong float double decimal
long long long long long long long long long CS0034 float double decimal
ulong CS0034 ulong CS0034 ulong ulong CS0034 ulong CS0034 ulong float double decimal
float float float float float float float float float float float double CS0019
double double double double double double double double double double double double CS0019
decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal CS0019 CS0019 decimal

符号有無、サイズ順

左\右 sbyte short int long byte ushort char uint ulong float double decimal
sbyte int int int long int int int long CS0034 float double decimal
short int int int long int int int long CS0034 float double decimal
int int int int long int int int long CS0034 float double decimal
long long long long long long long long long CS0034 float double decimal
byte int int int long int int int uint ulong float double decimal
ushort int int int long int int int uint ulong float double decimal
char int int int long int int int uint ulong float double decimal
uint long long long long uint uint uint uint ulong float double decimal
ulong CS0034 CS0034 CS0034 CS0034 ulong ulong ulong ulong ulong float double decimal
float float float float float float float float float float float double CS0019
double double double double double double double double double double double double CS0019
decimal decimal decimal decimal decimal decimal decimal decimal decimal decimal CS0019 CS0019 decimal

エラー

コード 意味
CS0034 型 'type1' および 'type2' のオペランドの演算子 'operator' があいまいです
CS0019 演算子 'operator' を 'type' と 'type' 型のオペランドに適用することはできません

まとめると

  • 整数と整数
    • 16ビット以下整数またはintの組み合わせはintになる
    • 32ビット以上符号なし整数 + 符号付き整数は符号なし整数より1つ大きい符号付き整数になる
      • uint + 符号付き整数はlongになる
      • ulong + 符号付き整数はCS0034エラーになる(ulongより大きい符号付き整数が基本の型にないから?)
    • 32ビット以上符号なし整数 + 符号なし整数は大きい方になる
      • uint + 32ビット以下符号なし整数はuintになる
      • ulong + 符号なし整数はulongになる
    • long + ulong以外の整数はlongになる
  • 整数と小数
    • 整数 + 小数は小数の方になる
  • 小数と小数
    • decimal + IEEE754はCS0019エラーになる
    • IEEE754の組み合わせは大きい方になる
      • float + doubleはdoubleになる

[CLSCompliant(true)]に限定すると

  • 整数と整数
    • int以下の組み合わせはintになる
    • longとの組み合わせはlongになる
  • 整数と小数
    • 整数 + 小数は小数の方になる
  • 小数と小数
    • decimal + IEEE754はCS0019エラーになる
    • IEEE754の組み合わせは大きい方になる
      • float + doubleはdoubleになる

すごいシンプルになりますね、ulongとかCLSCompliant(false)なのでCS0034の出番がなくなるし。

なんでこんな表を作っていたかというと

dynamicが使用できない設定にしたクラスライブラリ上でIComparable<T>なT型の値T fromからT toまでをステップ値がV型の値V stepで刻む(基本的にV=T想定だけど)IEnumerable<T>インターフェイス実装のクラスでnew Stepper(T from, T to, V step)みたいなことができるものを作りたくて

  • V stepが数値型でいう1相当の値だった場合はインクリメント演算子があればインクリメント演算子
  • V stepが数値型でいう-1相当の値だった場合はデクリメント演算子があればデクリメント演算子
  • V stepが上記以外か対応するインクリメント演算子またはデクリメント演算子がない場合は加算演算子

という演算子オーバーロードをリフレクション拾って実現できないかと小細工を用意してやってみたら

  • 圧倒的に出番があるはずの小文字の別名を持つ型の大半から演算子オーバーロードを取得できない(専用の仕組みで頑張っているらしい)
  • 演算子オーバーロードのあるdecimalもdecimalとの計算分しか用意していない(implicitとか見て頑張っているらしい)
  • int型の値をobject型の変数に格納したものを(long)ってやると型を合わせてくれるどころかエラーになるので、正確に戻した上でキャストする必要がある
    • 小文字の型は基本IConvertibleインターフェイスを実装していてToXXX()メソッドがあったり、Convert.ChangeType(object, Type)でどちらかの型に合わせるのは可能なので、あとは2つの型で来た時にどちらに合わせれば良いかの変換表を作れば良い

という感じの結果になってしまい、異なる型での計算時の対応表を作ったりしていたんですね。
他にも二項演算を自由にできるようにという厳密な型指定の言語で何しようとしているのお前みたいなことをしていました。
dynamicを使えればこの辺りは楽に書けるんですが、諸事情で今作っている部分には使えないので泥臭い実装をしています。(使える環境でも実行時にCS0034とCS0019の出るところはエラーになる)

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?