2010-07-06 7 views
3

У меня есть перечисление MyEnum (Neg -1; None 0; Pos 1).Отрицательный к -1, 0 к 0, Положительный к 1

Я использую результат CompareTo() для инициализации объекта этого перечисления.

Что является наиболее эффективным способом в .NET сделать это (Отрицательно -1, 0 до 0, Положительно к 1)?

NB.
CompareTo() возвращает целочисленное значение.

+0

'х/Математика.abs (x) ' – knittl

+2

@knittl: Считаете ли вы, что деление * наиболее показательно? – serhio

+9

@knittl делает .NET map '0/0' to' 0'? – Jeriko

ответ

13

Взгляните на Math.Sign

+0

Этот метод показывает наилучшие результаты, в соответствии с результатами испытаний ниже. – serhio

0

Если я правильно понимаю, вы хотите вернуть -1 для отрицательных значений, 0 для нулевых значений и 1 для положительных значений.

я бы с:

public static MyEnum GetSign(int value) 
{ 
    return value == 0 ? 0 : (MyEnum)(value/Math.Abs(value)); 
} 

Или я что-то не так?

+0

Прежде всего, CompareTo возвращает целочисленные значения, во-вторых, мне нужен наиболее эффективный способ. – serhio

+5

Мы находимся в 21 веке. afaik целые деления не медленнее, чем любые другие операции на современном процессоре. –

+1

Мое предположение: вы бы назвали это с помощью 'GetSign (a.compareTo (b));' – corsiKa

10

Как @Henrik и @knittl сказал, что вы должны использовать Math.Sign. Но если вам интересно, что делает инфраструктура .Net за кулисами, из Reflector появился следующий код.

public static int Sign(int value) 
{ 
    if (value < 0) 
    { 
    return -1; 
    } 
    if (value > 0) 
    { 
    return 1; 
    } 
    return 0; 
} 
+0

Меня интересует самый эффективный метод. Не работает ли пользовательская функция быстрее, чем встроенная? – serhio

+8

преждевременная оптимизация - это корень всего зла – knittl

+1

serhio, функция выше ** IS ** встроенная. – Kiril

0

Вы можете выбрать наиболее значимый бит переменной (в виде дополнения до двух, если старший бит равен 1, то есть отрицательное число). Если ваш самый старший бит равен 0, проверьте, равно ли значение 0. Верните значение соответствующим образом.

int Sign(int value){ 
    if (value >> 31) { //Shifts the variable over 31 places, if the MSB is 1, the statement is true 
     return -1; 
    } else { 
     if (value == 0){ 
      return 0; 
     } else { 
      return 1; 
     } 
    } } 

(отредактирован, например)

+0

Пример кода? – serhio

+0

@serhio: Это ваша домашняя работа, а не наша. – GvS

+0

@GvS: думая вот так, я должен искать ответ в книгах, а не спрашивать на форуме. Теперь, если я не знаю, как преобразовать отрицательный в -1, вы думаете, что я могу проверить самый старший бит в целочисленном? :) – serhio

3

Результат CompareTo отрицательный, нулевой или положительный. Если вы посмотрите на другие ответы, Math.Sign использует 2 оператора if для возврата int.

Просто перекодируйте Math.Sign, чтобы вернуть свой список.

(Если бы это была не домашняя работа, я бы привел здесь пример кода, но вы должны учиться на нем).

После этого проверьте его, чтобы посмотреть, что наиболее эффективно.

+0

Stevo3000 привел пример. – serhio

+0

Однако пример кода будет оценен. – serhio

+1

В то время, когда вы тратите на ожидание ответа, вы могли бы создать 10 примеров кода самостоятельно, сделали 20 вещей не так, и поэтому узнали 20 вещей, которые не содержатся в каком-либо примере кода ;-) – GvS

3

Результаты испытаний (Dual Core, x86):

''''''''''''''''''''' DEBUG MODE ''' 
= 1 = 
Division took 00:00:06.2482408 ms 
BuiltInSign took 00:00:05.0293383 ms <<< 
BitTestSign took 00:00:05.2092181 ms 
CustomSign took 00:00:05.2512802 ms 

= 2 = 
Division took 00:00:06.2477787 ms 
BuiltInSign took 00:00:05.0330921 ms <<< 
BitTestSign took 00:00:05.2114098 ms 
CustomSign took 00:00:05.2556966 ms 

= 3 = 
Division took 00:00:06.2506690 ms 
BuiltInSign took 00:00:05.0388615 ms <<< 
BitTestSign took 00:00:05.2306954 ms 
CustomSign took 00:00:05.2512391 ms 


''''''''''''''''''' RELEASE MODE ''' 
= 1 = 
Division took 00:00:01.0974078 ms 
BuiltInSign took 00:00:00.3195232 ms 
BitTestSign took 00:00:00.6392142 ms 
CustomSign took 00:00:00.3194230 ms <<< 

= 2 = 
Division took 00:00:01.1007138 ms 
BuiltInSign took 00:00:00.3197784 ms <<< 
BitTestSign took 00:00:00.6395294 ms 
CustomSign took 00:00:00.3202774 ms 

= 3 = 
Division took 00:00:01.0977087 ms 
BuiltInSign took 00:00:00.3194622 ms <<< 
BitTestSign took 00:00:00.6394220 ms 
CustomSign took 00:00:00.3201607 ms 

Код:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     Stopwatch sw = new Stopwatch(); 
     MyEnum myEnum = MyEnum.None; 

     const int max = 100000000; 

     sw.Start(); 
     for (int i = -max; i < max; i++) 
     { 
      myEnum = Division(i); 
     } 
     sw.Stop(); 
     Console.WriteLine("Division took {0} ms", sw.Elapsed); 
     sw.Reset(); 

     sw.Start(); 
     for (int i = -max; i < max; i++) 
     { 
      myEnum = BuiltInSign(i); 
     } 
     sw.Stop(); 
     Console.WriteLine("BuiltInSign took {0} ms", sw.Elapsed); 
     sw.Reset(); 

     sw.Start(); 
     for (int i = -max; i < max; i++) 
     { 
      myEnum = BitTestSign(i); 
     } 
     sw.Stop(); 
     Console.WriteLine("BitTestSign took {0} ms", sw.Elapsed); 
     sw.Reset(); 

     sw.Start(); 
     for (int i = -max; i < max; i++) 
     { 
      myEnum = CustomSign(i); 
     } 
     sw.Stop(); 
     Console.WriteLine("CustomSign took {0} ms", sw.Elapsed); 
    } 

    private MyEnum Division(int value) 
    { 
     return value == 0 ? 0 : (MyEnum)(value/Math.Abs(value)); 
    } 

    private MyEnum BuiltInSign(int value) 
    { 
     return (MyEnum)Math.Sign(value); 
    } 

    private MyEnum CustomSign(int value) 
    { 
     if (value < 0) 
      return MyEnum.Neg; 

     if (value > 0) 
      return MyEnum.Pos; 

     return MyEnum.None; 
    } 

    MyEnum BitTestSign(int value) 
    { 
     // Shifts the variable over 31 places, 
     // if the MSB is 1, the statement is true 
     if ((value >> 31) == 1) 
     { 
      return MyEnum.Neg; 
     } 
     else 
     { 
      if (value == 0) 
      { 
       return MyEnum.None; 
      } 
      else 
      { 
       return MyEnum.Pos; 
      } 
     } 
    } 

    private enum MyEnum 
    { 
     Pos = 1, 
     None = 0, 
     Neg = -1 
    } 
} 
+0

В CustomSign, почему вы возвращаете (MyEnum) (- 1) 'вместо' return MyEnum.Pos'? Почему «MyEnum.Pos» - отрицательное число, и наоборот от вашего первоначального вопроса? – GvS

+0

Разве ваш тестовый набор не имеет отрицательных чисел? Теперь вы не измеряете perf для негативов, это должно быть иначе. – GvS

+0

обновлено ......... – serhio

1

.NET внутренне хранит Интс как дополнение. Итак, если вы хотите попробовать что-то еще, проверьте и проверьте, установлен ли самый старший бит. Это может быть или не быть быстрее, но оно должно легко вписаться в вашу тестовую структуру.

Псевдокод:

if(num == 0) 
    return 0; 

if(num has msb set) 
    return -1; 

return 1; 
+0

Этот метод не является оптимальным, см. Результаты теста. – serhio

+1

Этот метод быстрее, чем Math.Sign на моей машине. –

+0

@s_hewitt: Но на моем, медленнее, см. Результат теста ... – serhio

Смежные вопросы