Реализация .NET: двойное преобразование в математике.Мин (поплавок, поплавок)


Почему .Net реализует математику.Функция Min (float, float) выглядит так:

public static float Min(float val1, float val2)
{
  if ((double) val1 < (double) val2 || float.IsNaN(val1))
    return val1;
  else
    return val2;
}
Хотя я вижу использование IsNaN, я не понимаю, почему они преобразуются в double при сравнении значений. Разве это не медленнее, чем просто писать val < val 2? Особенно если я хотел использовать его, чтобы закрепить значение в числах без особой точности, как 0f или 1f.

Должен ли я просто пойти вперед и реализовать пользовательскую математическую библиотеку, которая дополнительно также требует иметь значения non NaN, чтобы получить лучшее представление или это пустая трата времени?

public static float Min(float a, float b)
{
    return a < b ? a : b;
}
4 4

4 ответа:

Да, я использовал Resharper, который делает именно это

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

  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  public static float Min(float val1, float val2) {
    if (val1 < val2)
        return val1;

    if (Single.IsNaN(val1))
        return val1;

    return val2;
  }
Трудно догадаться, почему Решарпер делает это, я бы с готовностью предположил, что это просто ошибка. Отдавайте предпочтение исходному коду, доступному от Microsoft, не только для точности, но и комментарии тоже хороши.

Я не могу сказать вам, почему они решили бросить float в double Для сравнения, но я сомневаюсь, что это вызовет какое-либо заметное или значительное влияние скорости на вашу программу. Я бы просто использовал встроенную функцию.

Нет такой вещи, как математика.Мин(поплавок, поплавок). .NET содержит только определение для Min (double, double). Проверьте MSDN: http://msdn.microsoft.com/en-us/library/system.math.min (v=против 100).aspx

EDIT: есть, спасибо @gideon http://msdn.microsoft.com/en-us/library/070xee48.aspx

В общем случае нельзя считать, что Single работает быстрее, чем Double. Регистры с плавающей запятой на процессоре Intel составляют 80 бит, и операции с плавающей запятой на процессоре выполняются с использованием этой точности. На этой платформе JIT может генерировать команды с плавающей запятой, которые загружают аргументы в собственные 80-битные регистры, и единственная разница заключается в том, что регистры загружаются из 32-битных или 64-битных ячеек памяти. Возможно, исполнители Math.Min основывали свою реализацию на сложные знания о том, как JIT-компилятор генерирует код с плавающей запятой.

Из принятого ответа видно, что вопрос основан на неверном предположении (что существует приведение от Single к Double). Чтобы выяснить, действительно ли приведение имеет значение, я посмотрел на ассемблер, сгенерированный функцией Min с приведением и без приведения.

Это .NET framework Math.Min(Single, Single) , как показано в моем отладчике:

00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  fld         dword ptr [ebp+0Ch] 
00000006  fld         dword ptr [ebp+8] 
00000009  fxch        st(1) 
0000000b  fcomi       st,st(1) 
0000000d  jp          00000015 
0000000f  jae         00000015 
00000011  fstp        st(1) 
00000013  jmp         00000022 
00000015  fcomi       st,st(0) 
00000017  jp          0000001B 
00000019  je          00000026 
0000001b  mov         eax,1 
00000020  jmp         00000028 
00000022  pop         ebp 
00000023  ret         8 
00000026  xor         eax,eax 
00000028  test        eax,eax 
0000002a  je          00000030 
0000002c  fstp        st(1) 
0000002e  jmp         00000036 
00000030  fstp        st(0) 
00000032  pop         ebp 
00000033  ret         8 
00000036  pop         ebp 
00000037  ret         8 

Вот сборка для функции, использующей приведите к Double точно так же, как в вопросе:

00000000  push        ebp 
00000001  mov         ebp,esp 
00000003  sub         esp,8 
00000006  fld         dword ptr [ebp+0Ch] 
00000009  fld         dword ptr [ebp+8] 
0000000c  fld         st(1) 
0000000e  fstp        qword ptr [ebp-8] 
00000011  fld         qword ptr [ebp-8] 
00000014  fld         st(1) 
00000016  fstp        qword ptr [ebp-8] 
00000019  fld         qword ptr [ebp-8] 
0000001c  fcomip      st,st(1) 
0000001e  fstp        st(0) 
00000020  jp          00000028 
00000022  jbe         00000028 
00000024  fstp        st(0) 
00000026  jmp         00000043 
00000028  fxch        st(1) 
0000002a  fcomi       st,st(0) 
0000002c  jp          00000030 
0000002e  je          00000037 
00000030  mov         eax,1 
00000035  jmp         00000039 
00000037  xor         eax,eax 
00000039  test        eax,eax 
0000003b  jne         00000041 
0000003d  fstp        st(0) 
0000003f  jmp         00000049 
00000041  fstp        st(1) 
00000043  mov         esp,ebp 
00000045  pop         ebp 
00000046  ret         8 
00000049  mov         esp,ebp 
0000004b  pop         ebp 
0000004c  ret         8 

Есть еще несколько инструкций, и они, вероятно, немного снизят производительность функции.