Где код, который делает деление с плавающей точкой для C #? - PullRequest
0 голосов
/ 28 сентября 2019

Вопрос

Я хотел бы увидеть фрагмент кода, который выполняет деление с плавающей запятой и возвращает Infinity при делении на ноль.Где я могу его найти?

Пример кода

Мотивация желания узнать, что происходит из этого кода, взято из документации .NET.Я бы ожидал получить DivideByZeroException, но вместо этого я получил Infinity.

https://docs.microsoft.com/en-us/dotnet/api/system.dividebyzeroexception?view=netframework-4.8#remarks

using System;

public class Example
{
   public static void Main()
   {
      int number1 = 3000;
      int number2 = 0;

      Console.WriteLine((double)number1 / number2);
   }
}
// The example displays the following output:
//        Infinity

Документация

Я нашел документацию о том, что плавающийделение на ноль-точку не вызывает исключение, поэтому это нормально:

https://docs.microsoft.com/en-us/dotnet/api/system.dividebyzeroexception?view=netframework-4.8#remarks

Деление значения с плавающей точкой на ноль не вызывает исключения;это приводит к положительной бесконечности, отрицательной бесконечности или не числу (NaN), в соответствии с правилами IEEE 754.Поскольку в следующем примере используется деление с плавающей точкой, а не целочисленное деление, операция не вызывает исключение DivideByZeroException.

Код в .NET Framework

В Visual Studio я завис надзнак деления "/" и Resharper показывают

double double.operator /(double left, double right)

И теперь я хотел бы увидеть реализацию этого, чтобы увидеть, как возвращается Infinity.Но я не могу его найти.

Я проверял здесь

, но не вижу оператора деления.

Приведенная выше ссылка приведет меня сюда

, но также ничего о деталях реализации.

Я также посмотрел здесь

но смотрите только закомментированный код

///        Double IArithmetic<Double>.Divide(Double divisor, out bool overflowed) {
///            Double s = m_value / divisor;
///            overflowed = IsInfinity(s) || IsNaN(s);
///            return s;
///        }

Также ничего в реализации Double corefx :

Я бы ожидал, что что-то понравилось (псевдокод):

public static double operator /(double left, double right)
{
   if (right == 0)
   {
      return double.Infinity;
   }
   else
   {
      ...
   }
}

1 Ответ

0 голосов
/ 28 сентября 2019

Ваш код компилируется в следующий CIL:

.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       21 (0x15)
  .maxstack  2
  .locals init (int32 V_0,
           int32 V_1)
  IL_0000:  nop
  IL_0001:  ldc.i4     0xbb8
  IL_0006:  stloc.0
  IL_0007:  ldc.i4.0
  IL_0008:  stloc.1
  IL_0009:  ldloc.0
  IL_000a:  conv.r8
  IL_000b:  ldloc.1
  IL_000c:  conv.r8
  IL_000d:  div
  IL_000e:  call       void [mscorlib]System.Console::WriteLine(float64)
  IL_0013:  nop
  IL_0014:  ret
} // end of method Example::Main

Этот вызов IL_000d: div является происходящей операцией деления.Это означает, что CLR выполнит работу, поэтому вы не найдете никакого исходного кода, выполняющего эту работу.Если мы углубимся в исходный код CLR (здесь показан coreclr) для оператора деления для значений с плавающей запятой:

TFp FpDiv(TFp dividend, TFp divisor)
{
#ifdef _TARGET_ARMARCH_
    // From the ECMA standard:
    //
    // If [dividend] is zero and [divisor] is zero
    //   the result is NaN.
    // If [dividend] is infinity and [divisor] is infinity
    //   the result is NaN.

    if (dividend == 0 && divisor == 0)
    {
        return TFpTraits::NaN();
    }
    else if (!_finite(dividend) && !_isnan(dividend) && !_finite(divisor) && !_isnan(divisor))
    {
        return TFpTraits::NaN();
    }
#endif // _TARGET_ARMARCH_

    return dividend / divisor;
}

Вы можете увидеть, что он обрабатывает некоторые предварительные условия, а затем вызывает внутреннюю операцию компилятора.На x86 это, в свою очередь, будет вызовом FDIV, который задокументирован как поднятие флага деления на ноль, и среда выполнения C благодаря IEEE 754 превратится в бесконечность.Эта бесконечность работает по пути к вашему приложению на C #.

...