我正在研究C#编译器并尝试理解数学运算规则。
我发现==
算子在两种不同的原始类型之间存在一种难以理解的行为。
int a = 1;
float b = 1.0f;
Console.WriteLine(a == b);
这实际上编译为
.locals init (
[0] int32,
[1] float32
)
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0
IL_0003: ldc.r4 1
IL_0008: stloc.1
IL_0009: ldloc.0
IL_000a: conv.r4
IL_000b: ldloc.1
IL_000c: ceq
意思是
(float)a == (float)b
我的期望是(int)a == (int)b
,因为左边的价值是integer
。
这个结果的原因是什么?
int->float
比float->int
快这实际上与速度无关(正如你的建议),而且与隐式转换有关,你可以在C# Specifications找到数字促销主题下定义的相关信息。
12.4.7数字促销
数字提升包括自动执行预定义一元和二元数字运算符的操作数的某些隐式转换。数字提升不是一种独特的机制,而是将重载决策应用于预定义运算符的效果。尽管可以实现用户定义的运算符以表现出类似的效果,但数字促销特别不会影响用户定义的运算符的评估。
作为数字提升的示例,请考虑binary *运算符的预定义实现:
int operator *(int x, int y); uint operator *(uint x, uint y); long operator *(long x, long y); ulong operator *(ulong x, ulong y); float operator *(float x, float y); double operator *(double x, double y); decimal operator *(decimal x, decimal y);
当重载决策规则(第12.6.4节)应用于这组运算符时,效果是从操作数类型中选择存在隐式转换的第一个运算符。
更多
二进制数字促销发生在预定义的
+
,–
,*
,/
,%
,&
,|
,^
,==
,!=
,>
,<
,>=
和<=
二元运算符的操作数上。二进制数字提升隐式地将两个操作数转换为公共类型,在非关系运算符的情况下,它也成为操作的结果类型。二进制数字促销包括按照它们在此处显示的顺序应用以下规则:
- 如果任一操作数的类型为十进制,则另一个操作数将转换为十进制类型,或者如果另一个操作数的类型为float或double,则会发生绑定时错误。
- 否则,如果任一操作数的类型为double,则另一个操作数将转换为double类型。
- 否则,如果任一操作数的类型为float,则另一个操作数将转换为float类型。
- 否则,如果任一操作数的类型为ulong,则另一个操作数将转换为ulong类型,或者如果另一个操作数的类型为sbyte,short,int或long,则会发生绑定时错误。
- 否则,如果任一操作数的类型为long,则另一个操作数将转换为long类型。
- 否则,如果任一操作数的类型为uint而另一个操作数的类型为sbyte,short或int,则两个操作数都将转换为long类型。
- 否则,如果任一操作数的类型为uint,则另一个操作数将转换为类型uint。
- 否则,两个操作数都将转换为int类型。
您可以通过他们展示的示例来了解这一点
byte b = 1;
short a = 2;
WriteLine((int)b==(int)s); // promotes both to int
int i = 1;
double d = 2;
WriteLine((double)i==d); // promotes i to double
或者你的例子
int a = 1;
float b = 1.0f;
WriteLine((float)a==b); // promotes a to float