Почему (int) == (float) всегда компилируется в (float) == (float) - PullRequest
1 голос
/ 11 апреля 2019

Я исследую компиляторы 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

1 Ответ

8 голосов
/ 11 апреля 2019

Это на самом деле не имеет ничего общего с скорость (как вы предлагаете) и больше с Неявные преобразования , вы можете найти соответствующую информацию, определенную в разделе Числовые Акции в C # Технические характеристики

12.4.7 Числовые акции

Числовое продвижение состоит из , автоматически выполняющих определенные неявные преобразования операндов предопределенных унарных и двоичные числовые операторы . Числовое продвижение не является четким механизм, а скорее эффект применения разрешения перегрузки к предопределенные операторы . Числовое продвижение конкретно не влияет оценка пользовательских операторов , хотя пользовательских операторов может быть реализован для демонстрации подобных эффектов.

В качестве примера числовое продвижение , рассмотрим предопределенный реализации бинарного оператора * :

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) применяются к этому набору операторов , , эффект заключается в выборе первого из операторов для какие неявные преобразования существуют из операндов типов.

Далее Подробнее

Двоичное числовое продвижение происходит для операндов предопределенного +, , *, /, %, &, |, ^, ==, !=, >, <, >= и <= бинарные операторы. Двоичное числовое продвижение неявно преобразует оба операнда в общий тип, который в случае нереляционных операторов также становится тип результата операции. Двоичное числовое продвижение состоит из применяя следующие правила, в порядке их появления здесь:

  • Если один из операндов имеет тип decimal, другой операнд преобразуется в тип decimal или возникает ошибка времени привязки, если другой операнд типа float или double.
  • В противном случае, если один из операндов имеет тип double, другой операнд преобразуется в тип double.
  • В противном случае, если один из операндов имеет тип float, другой операнд преобразуется в тип float.
  • В противном случае, если один из операндов имеет тип ulong, другой операнд преобразуется в тип ulong или возникает ошибка времени привязки, если другой операнд имеет тип sbyte, short, int или long.
  • В противном случае, если один из операндов имеет тип long, другой операнд преобразуется в тип long.
  • В противном случае, если один из операндов имеет тип uint, а другой операнд имеет тип sbyte, short или int, оба операнда преобразуются в тип долго.
  • В противном случае, если один из операндов имеет тип 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
...