Czy mogę zamienić długie na int?

142

Chcę przekonwertować longna int.

Jeśli wartość long> int.MaxValue, z przyjemnością pozwolę jej się zawinąć.

Jaka jest najlepsza droga?

pomimo
źródło

Odpowiedzi:

218

Po prostu zrób (int)myLongValue. Zrobi dokładnie to, co chcesz (odrzucając MSB i biorąc LSB) w uncheckedkontekście (który jest domyślny kompilatora). To będzie rzucać OverflowExceptionsię w checkedkontekście, jeśli wartość nie mieści się w sposób int:

int myIntValue = unchecked((int)myLongValue);
Mehrdad Afshari
źródło
15
Dla każdego, kto miał to samo pytanie, co ja: Zauważ, że odrzucenie MSB może mieć wpływ na znak wyniku. Z powyższym myIntValuemoże skończyć się ujemnie, gdy myLongValuejest dodatnie ( 4294967294 => -2) i odwrotnie ( -4294967296 => 0). Na przykład podczas wykonywania CompareTooperacji nie można szczęśliwie rzutować wyniku odejmowania jednego longod drugiego na an inti zwracać to; w przypadku niektórych wartości porównanie dałoby niepoprawny wynik.
TJ Crowder
21
@Chris: new Random()używa Environment.TickCountpod maską; nie ma potrzeby ręcznego wysiewu z tyknięciem zegara.
Mehrdad Afshari
@MehrdadAfshari czy zawsze tak było?
Chris Marisic
3
Mimo że było to lata temu, powodem, dla którego użyłem go w nowym Random, było to, że uzyskiwałem te same dokładne wyniki w teście jednostkowym i chciałem wariancji. Użycie liczby dało mi wariancję.
Chris Marisic,
3
Kontekst domyślny jest uncheckedtaki, więc jeśli nie zmieniłeś go wyraźnie, to uncheckedsłowo kluczowe (jak pokazano w tej odpowiedzi i komentarzu @ ChrisMarisic itp.) Nie jest potrzebne i int myIntValue = (int)myLongValuejest dokładnie równoważne. Należy jednak pamiętać, że niezależnie od tego, czy używasz uncheckedsłowa kluczowego, czy nie, otrzymujesz niematematyczne, niegrzeczne zachowanie obcinania opisane przez @TJCrowder, w którym znak może się odwrócić w niektórych przypadkach przepełnienia. Jedynym sposobem, aby naprawdę zapewnić matematyczną poprawność, jest użycie checked(...)kontekstu, w którym te przypadki rzucą wyjątek.
Glenn Slayden
35
Convert.ToInt32(myValue);

Chociaż nie wiem, co się stanie, gdy będzie większe niż int.MaxValue.

Max Schmeling
źródło
42
„Chociaż nie wiem, co zrobi, gdy jest większe niż int.MaxValue” Wyrzuci an OverflowException, a jest to dokładnie to, czego OP nie chce: msdn.microsoft.com/en-us/library/d4haekc4.aspx
TJ Crowder
4
Sprawdź, czy myValue> Integer.Max przed uruchomieniem konwersji, jeśli musisz wykonać inne przetwarzanie, gdy myValue> Integer.Max. Convert.ToInt32 (myValue) przepełni się (bez wyjątku, jak sądzę) w przeciwnym razie. Ta metoda działa również w VB.NET.
TamusJRoyce
3
Chociaż (int) jest poprawne, Convert jest lepszą odpowiedzią. Lepiej mieć dziwne wyjątki niż dziwne dane.
Richard czerwca,
1
@RichardJune Um, nie? OP tutaj wyraźnie mówi: „ Jeśli wartość long> int.MaxValue, z przyjemnością pozwolę jej się zawinąć. ” Widzę, jak ogólnie spierać się o twoje stwierdzenie, ale w tym konkretnym przypadku nie, Convertnie jest dobre.
ruffin
if (value > Int32.MaxValue) return Int32.MaxValue; else return Convert.ToInt32( value );
Sergey
15

Czasami nie interesuje Cię rzeczywista wartość, ale jej użycie jako suma kontrolna / kod skrótu . W takim przypadku metoda wbudowana GetHashCode()jest dobrym wyborem:

int checkSumAsInt32 = checkSumAsIn64.GetHashCode();
realbart
źródło
7
Minęło trochę czasu, odkąd udzielono tej odpowiedzi, chociaż chcę wspomnieć, że implementacja hashcode może się różnić między wersjami .NET. W rzeczywistości może się to nie dziać, ale nie ma gwarancji, że ta wartość jest taka sama dla różnych uruchomień aplikacji / domen aplikacji.
Caramiriel
1
Aby dodać do tego, co mówi @Caramiriel: jeśli używasz jako tymczasowego , podczas bieżącej sesji aplikacji, GetHashCodejest to właściwy wybór. Jeśli szukasz trwałej sumy kontrolnej - wartości, która będzie taka sama, gdy później uruchomisz aplikację, nie używaj GetHashCode, ponieważ nie gwarantuje się, że będzie to ten sam algorytm na zawsze.
ToolmakerSteve
9

Najbezpieczniejszym i najszybszym sposobem jest użycie maskowania bitów przed wysłaniem ...

int MyInt = (int) ( MyLong & 0xFFFFFFFF )

Wartość maski bitowej ( 0xFFFFFFFF) będzie zależeć od rozmiaru Int, ponieważ rozmiar Int zależy od maszyny.

Mashake
źródło
Musisz zdecydować, co chcesz zrobić, gdy wynik będzie przepełniony lub stanie się liczbą ujemną. To, co pokazujesz, nadal będzie przepełnione, IIRC, ponieważ przepuszczasz znak. [Jak wspomniano w innej odpowiedzi, w uncheckedkontekście nie otrzymasz przepełnienia - ale nie musisz maskować się, uncheckedaby uniknąć przepełnienia, więc rozwiązanie jest potrzebne tylko w checkedkontekście.] Przykład dla 16-bitów. Podpisane blokady 16-bitowe (-32768, 32767). Maskowanie za pomocą 0xFFFF dopuszcza wartość do 65535, powodując przepełnienie, IIRC. Może maskować, aby uniknąć bitu znaku, 0x7FFF lub 0x7FFFFFFF, jeśli chcesz tylko dodatnie.
ToolmakerSteve
1

Może konwertować według

Convert.ToInt32

Ale zgłosi OverflowException, jeśli wartość jest poza zakresem typu Int32. Podstawowy test pokaże nam, jak to działa:

long[] numbers = { Int64.MinValue, -1, 0, 121, 340, Int64.MaxValue };
int result;
foreach (long number in numbers)
{
   try {
         result = Convert.ToInt32(number);
        Console.WriteLine("Converted the {0} value {1} to the {2} value {3}.",
                    number.GetType().Name, number,
                    result.GetType().Name, result);
     }
     catch (OverflowException) {
      Console.WriteLine("The {0} value {1} is outside the range of the Int32 type.",
                    number.GetType().Name, number);
     }
}
// The example displays the following output:
//    The Int64 value -9223372036854775808 is outside the range of the Int32 type.
//    Converted the Int64 value -1 to the Int32 value -1.
//    Converted the Int64 value 0 to the Int32 value 0.
//    Converted the Int64 value 121 to the Int32 value 121.
//    Converted the Int64 value 340 to the Int32 value 340.
//    The Int64 value 9223372036854775807 is outside the range of the Int32 type.

Tutaj jest dłuższe wyjaśnienie.

nzrytmn
źródło
0

Nie

(int) Math.Min(Int32.MaxValue, longValue)

być właściwą drogą, mówiąc matematycznie?

Rémy Esmery
źródło
To zacisnąćlongValue do najbliższego reprezentowana intjeśli wartość jest ogromna. Brakuje jednak takiego samego traktowania zbyt ujemnych danych wejściowych, które zamiast tego tracą najbardziej znaczące bity; musiałbyś też porównać Int32.MinValue. Oryginalny plakat nie wydawał się jednak chcieć zaciskania.
Jeppe Stig Nielsen
IMHO czasami lepiej jest uzyskać wyjątek niż złą wartość, którą Int32.MaxValue byłoby ...
G. Goncharov
0

Poniższe rozwiązanie spowoduje obcięcie do int.MinValue / int.MaxValue, jeśli wartość wykracza poza granice całkowite.

myLong < int.MinValue ? int.MinValue : (myLong > int.MaxValue ? int.MaxValue : (int)myLong)
Łaskawy
źródło
0

Możliwym sposobem jest użycie operatora modulo, aby pozostawić wartości tylko w zakresie int32, a następnie rzutować je na int.

var intValue= (int)(longValue % Int32.MaxValue);
Andre
źródło