Могу ли я преобразовать long в int?

145

Я хочу преобразовать longв int.

Если значение long> int.MaxValue, я с радостью позволю ему обернуться.

Как лучше всего?

несмотря
источник

Ответы:

220

Просто сделай (int)myLongValue. Он будет делать именно то, что вы хотите (отбрасывая MSB и принимая LSB) в uncheckedконтексте (который является компилятором по умолчанию). Он будет вставлен OverflowExceptionв checkedконтекст, если значение не соответствует int:

int myIntValue = unchecked((int)myLongValue);
Мехрдад Афшари
источник
15
Для всех, у кого был тот же вопрос, что и я: обратите внимание, что отказ от MSB может повлиять на знак результата. С вышесказанным myIntValueможет оказаться отрицательным, когда myLongValueположительно ( 4294967294 => -2), и наоборот ( -4294967296 => 0). Так CompareTo, например, при реализации операции вы не можете успешно longпреобразовать результат вычитания одного из другого intи вернуть его; для некоторых значений сравнение даст неверный результат.
TJ Crowder
21
@Chris: new Random()использует Environment.TickCountпод капотом; нет необходимости засеивать вручную по тикам часов.
Mehrdad Afshari 08
3
По умолчанию используется контекст unchecked, поэтому, если вы явно не изменили его, uncheckedключевое слово (как показано в этом ответе и комментарии @CrisMarisic и т. Д.) Не требуется и int myIntValue = (int)myLongValueполностью эквивалентно. Однако обратите внимание, что независимо от того, используете ли вы uncheckedключевое слово или нет, вы получаете нематематическое грубое усечение, описанное @TJCrowder, когда знак может перевернуться в некоторых случаях переполнения. Единственный способ по-настоящему гарантировать математическую корректность - использовать checked(...)контекст, в котором эти случаи вызовут исключение.
Glenn
35
Convert.ToInt32(myValue);

Хотя я не знаю, что он будет делать, если он больше int.MaxValue.

Макс Шмелинг
источник
44
«Хотя я не знаю, что он будет делать, если он больше int.MaxValue» Он выдаст OverflowException, а это именно то, чего OP не хочет: msdn.microsoft.com/en-us/library/d4haekc4.aspx
TJ Crowder
4
Проверьте, если myValue> Integer.Max перед запуском преобразования, если вам нужно выполнить другую обработку, когда myValue> Integer.Max. Convert.ToInt32 (myValue) в противном случае будет переполняться (я полагаю, без исключения). Этот метод также работает в VB.NET.
TamusJRoyce 06
3
Хотя (int) допустимо, Convert - лучший ответ. Лучше иметь странные исключения, чем странные данные.
Ричард июнь
1
@RichardJune Эм, нет? OP здесь явно говорит: « Если значение long> int.MaxValue, я рад позволить ему обернуться ». Я вижу, как аргументируется ваше утверждение в целом, но в данном конкретном случае нет, Convertэто нехорошо.
ruffin
if (value > Int32.MaxValue) return Int32.MaxValue; else return Convert.ToInt32( value );
Сергей
15

Иногда вас действительно интересует не фактическое значение, а его использование в качестве контрольной суммы / хэш-кода . В этом случае GetHashCode()хорошим выбором будет встроенный метод :

int checkSumAsInt32 = checkSumAsIn64.GetHashCode();
реалбарт
источник
7
Этот ответ был дан давно, но я хочу упомянуть, что реализация хэш-кода может отличаться в разных версиях .NET. На самом деле этого может и не происходить, но нет гарантии, что это значение будет одинаковым для разных запусков приложений / доменов приложений.
Caramiriel
1
Чтобы добавить к тому, что говорит @Caramiriel: при использовании в качестве временного хэш-кода во время текущего сеанса приложения GetHashCodeэто подходящий выбор. Если вам нужна постоянная контрольная сумма - значение, которое будет таким же, когда вы запустите приложение позже, то не используйте GetHashCode, поскольку не гарантируется, что это будет один и тот же алгоритм навсегда.
ToolmakerSteve
10

Самый безопасный и быстрый способ - использовать Bit Masking перед кастом ...

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

Значение Bit Mask ( 0xFFFFFFFF) будет зависеть от размера Int, потому что размер Int зависит от машины.

Машаке
источник
Необходимо решить, что вы хотите сделать, когда результат либо выльется за край, либо станет отрицательным числом. То, что вы показываете, все равно будет переполняться, IIRC, потому что вы пропускаете знак. [Как упоминалось в другом ответе, в uncheckedконтексте вы не получите переполнения, но вам не нужно маскироваться, uncheckedчтобы избежать переполнения, поэтому решение требуется только в checkedконтексте.] Пример для 16-бит. 16-битные со знаком (-32768, 32767). Маскирование с помощью 0xFFFF допускает значение до 65535, вызывая переполнение IIRC. Может маскировать, чтобы избежать бит знака, 0x7FFF или 0x7FFFFFFF, если нужен только положительный результат.
ToolmakerSteve
2

Возможный способ - использовать оператор по модулю, чтобы значения оставались только в диапазоне int32, а затем преобразовать его в int.

var intValue= (int)(longValue % Int32.MaxValue);
Андре
источник
Это сработало лучше всего для меня, поскольку все другие попытки побитовой маски преобразовали 281474976710656 (2 ^ 48) в 0.
GuiRitter
1

Следующее решение будет усечено до int.MinValue / int.MaxValue, если значение выходит за границы Integer.

myLong < int.MinValue ? int.MinValue : (myLong > int.MaxValue ? int.MaxValue : (int)myLong)
Климент
источник
1

Он может конвертировать

Convert.ToInt32 метод

Но он вызовет исключение OverflowException, если значение выходит за пределы диапазона типа Int32. Базовый тест покажет нам, как это работает:

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.

Здесь есть более подробное объяснение.

nzrytmn
источник
0

Не стал бы

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

быть правильным, математически говоря?

Реми Эсмери
источник
Это зажатьlongValue до ближайшего представимого , intесли исходное значение является огромным. Но ему не хватает такой же обработки слишком отрицательных входных данных, которые вместо этого потеряли бы наиболее значимые биты; вам также нужно будет сравнить Int32.MinValue. Однако исходный плакат, похоже, не нуждался в зажимах.
Jeppe Stig Nielsen
ИМХО, иногда лучше получить исключение, чем неправильное значение, которым было бы Int32.MaxValue ...
Г. Гончаров