2012-08-29 15 views
9

Czy istnieje prosta funkcja matematyczna, która porównuje liczby xiy i zwraca -1, gdy x jest mniejsze niż y, 1, gdy x jest większe niż y i 0, gdy " jest równy?Porównaj dwie liczby i zwróć -1, 0 lub 1

Jeśli nie, czy byłoby eleganckie rozwiązanie (bez żadnego if) do konwersji danych wyjściowych z Math.Max(x, y) do tych zwrotów? Myślałem o samodzielnym podzieleniu liczb, np. 123/123 = 1, ale spowoduje to problem dzielenia przez 0.

Odpowiedz

21

Dla ścisłego -1, 0 lub 1 wymogu, nie ma jednej metody, która jest zagwarantowana, aby to zrobić. Jednakże, można użyć kombinacji Int32.CompareTo i Math.Sign:

int value = Math.Sign(x.CompareTo(y)); 

Ewentualnie, jeśli jesteś zadowolony z normalnym CompareTo umowy, która jest tylko wyrażone w liczbach ujemnych i dodatnich, numery 0, można użyć CompareTo na własną rękę.

+0

Właściwie zaczynam się zastanawiać, czy zwracana wartość nie jest "Int32.CompareTo". w końcu wróć. W każdym przypadku twoja odpowiedź dostarcza potrzebnych mi metod i jest najlepszą odpowiedzią na moje pytanie. Tak zaakceptowana :) – Daan

+0

Czy możesz podać przykład, w którym 'Int32.CompareTo()' zwraca coś innego niż -1 | 0 | 1? –

+3

@ChrisGessler: Nie bez powodu - ale byłoby to całkowicie uzasadnione, aby to zrobić (biorąc pod uwagę dokumentację), i nie chciałbym * założyć *, że nigdy tego nie zrobi. –

2

Jest to funkcja Math.Sign().

Jak to:

return Math.Sign(x-y); 
+0

Hmm, dół: dlaczego to źle? – RBarryYoung

+2

Moje zgłoszenie dotyczyło twojego "Math.Sign" bez dalszych wyjaśnień, teraz usunięte. Ale z 'x-y', źle zachowuje się w przepełnieniu. – hvd

2

Użyj funkcji CompareTo()

int i = 5; 
int n = 6; 

int c = i.CompareTo(n); 

ja zazwyczaj używają go w if oświadczenia:

int x = 34; 
int y = 25; 

if(x.CompareTo(y) == 0) 
{ 
    Console.WriteLine("Yes, they are equal"); 
} 
else 
{ 
    Console.WriteLine("No, they are not equal"); 
} 

Edit:

Po tym, jak niektórzy twierdzili, że Int32.CompareTo() może zwrócić coś innego niż -1 | 0 | 1, postanowiłem sam zbadać tę możliwość.

Oto odbitym kodem dla Int32.CompareTo(). Nie widzę, by ktokolwiek zwrócił cokolwiek poza -1 | 0 | 1.

[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] 
public int CompareTo(int value) 
{ 
    if (this < value) 
    { 
     return -1; 
    } 
    if (this > value) 
    { 
     return 1; 
    } 
    return 0; 
} 


public int CompareTo(object value) 
{ 
    if (value == null) 
    { 
     return 1; 
    } 
    if (!(value is int)) 
    { 
     throw new ArgumentException(Environment.GetResourceString("Arg_MustBeInt32")); 
    } 
    int num = (int) value; 
    if (this < num) 
    { 
     return -1; 
    } 
    if (this > num) 
    { 
     return 1; 
    } 
    return 0; 
} 
+3

Należy zauważyć, że nie ma gwarancji, że zwróci -1 lub 1. –

+0

Prawda ... może zwrócić 0. –

+2

Nie, chodzi mi o to, że może zwrócić 100 lub coś w tym stylu. –

4
x.CompareTo(y) 

Prosto z MSDN.

+1

Aktualizowanie tego, ponieważ strona MSDN pokazuje, jak zmusić wartość do -1/0/+ 1. Bez tego 'CompareTo()' faktycznie nie robi tego, co chce OP. – egrunin

+0

@egrunin - Nie widzę w artykule, w którym pokazuje, jak zmusić wartość do -1/0/+ 1. Jeśli odnosisz się do rzutowania do wyliczenia Porównanie, "(Porównanie) 100" nadal będzie wynosić 100, a nie 1. –

+0

Nie uruchomiłem tego kodu, ale * pojawia się *, aby twierdzić, że '(Porównanie) 100' zwróci 'Comparison.GreaterThan', który (jeśli następnie zostanie rzutowany na' int') będzie równy 1. – egrunin

0

można spróbować z tym kodem

var result = a.CompareTo(b); 
0

Użyj metody CompareTo na liczbę całkowitą:

public int c(int x, int y) 
{ 
    return x.CompareTo(y); 
} 

void Main() 
{  
    Console.WriteLine(c(5,3)); 
    Console.WriteLine(c(3,3)); 
    Console.WriteLine(c(1,3)); 
} 
11

Możesz to zrobić bez korzystania z żadnych połączeń .NET w ogóle i na 1 linii. UWAGA: Math.Sign i type.CompareTo oba używają logicznych instrukcji if i operatorów porównania, które powiedziałeś, że chciałbyś uniknąć.

int result = (((x - y) >> 0x1F) | (int)((uint)(-(x - y)) >> 0x1F)); 

jako funkcja

//returns 0 if equal 
//returns 1 if x > y 
//returns -1 if x < y 
public int Compare(int x, int y) 
{ 
    return (((x - y) >> 0x1F) | (int)((uint)(-(x - y)) >> 0x1F)); 
} 

Zasadniczo, wszystko to robi jest SHIFT bity znak aż do pierwszej pozycji.Jeśli wynik jest niepodpisany, wówczas będzie wynosił 0; następnie wykonuje tę samą operację i odwraca bity znaków, a następnie wynik jest pomarszczony 1, 0 lub -1.

Przypadek, gdy wynik jest -1

IS 12 > 15: 

12 - 15 = -3   (11111111111111111111111111111101) 
-3 >> 0x1F = -1   (11111111111111111111111111111111) 

-(12 - 15) = 3   (00000000000000000000000000000011) 
3 >> 0x1F = ((uint)0)=0 (00000000000000000000000000000000) cast to uint so 0 

    11111111111111111111111111111111 
OR 
    00000000000000000000000000000000 
= 11111111111111111111111111111111 (-1) 

Przypadek, gdy wynik jest 1

IS 15 > 12: 

15 - 12 = 3    (00000000000000000000000000000011) 
3 >> 0x1F = 0    (00000000000000000000000000000000) 

-(15 - 12) = -3   (11111111111111111111111111111101) 
-3 >> 0x1F = ((uint)-1)=1 (00000000000000000000000000000001) cast to uint so 1 

    00000000000000000000000000000000 
OR 
    00000000000000000000000000000001 
= 00000000000000000000000000000001 (1) 

Przypadek, gdy wynik jest 0

IS 15 == 15: 

15 - 15 = 0    (00000000000000000000000000000000) 
0 >> 0x1F = 0    (00000000000000000000000000000000) 

-(15 - 15) = 0   (00000000000000000000000000000000) 
0 >> 0x1F = ((uint)0)=0 (00000000000000000000000000000000) cast to uint so 1 

    00000000000000000000000000000000 
OR 
    00000000000000000000000000000000 
= 00000000000000000000000000000000 (0) 

ta powinna być również o wiele szybciej niż przy użyciu dowolnego wywołania matematyki lub innych metod .NET.

Powiązane problemy