Как мне преобразовать десятичное число в int в C #?

227

Как мне преобразовать десятичную в целое?

Роб Хруска
источник
11
Было бы полезно узнать, хотите ли вы округлить до ближайшего целого числа или просто отбросить числа после десятичной дроби (то есть: всегда округлять)
Дина
128
я, честно говоря, не вижу смысла в опровержении подлинных вопросов. да, ответ можно найти в Google, но разве это не улучшит качество сайта, если люди перестанут закрывать каждый второй вопрос? не то, чтобы этот вопрос был спамом или чем-то еще, и я уверен, что это будет полезно для многих
новичков

Ответы:

268

Используйте Convert.ToInt32из , mscorlibкак в

decimal value = 3.14m;
int n = Convert.ToInt32(value);

Смотрите MSDN . Вы также можете использовать Decimal.ToInt32. Опять же, смотрите MSDN . Наконец, вы можете сделать прямой бросок, как в

decimal value = 3.14m;
int n = (int) value;

который использует явный оператор приведения. Смотрите MSDN .

Ясон
источник
10
Остерегайтесь: Конверт имеет некоторое удивительное поведение для определенного преобразования (по nullсравнению 0с ""). Я бы рекомендовал никогда не использовать Convert, если вам абсолютно не нужна его гибкость (то есть в динамически типизированных сценариях)
Имон Нербонн
1
-1, так как это не будет работать для таких значений, как decimal.MaxValue и decimal.MinValue и приводит к OverflowException. Я считаю, что @Will дает лучший ответ здесь stackoverflow.com/a/501165/39532
мезоид
8
Будьте осторожны, потому что Convert.ToInt32и Decimal.ToInt32ведите себя по-другому. Из MSDN: Decimal.ToInt32- возвращаемое значение является неотъемлемой частью десятичного значения; дробные цифры усекаются . Convert.ToInt32- Возвращаемое значение округляется до ближайшего 32-разрядного целого числа со знаком. Если значение находится посередине между двумя целыми числами, возвращается четное число; то есть 4,5 преобразуется в 4, а 5,5 преобразуется в 6.
Везуччи
67

Ты не можешь

Ну, конечно, вы могли бы , однако int (System.Int32) недостаточно велик, чтобы содержать все возможные десятичные значения.

Это означает, что если вы приведете десятичное число, которое больше, чем int.MaxValue, вы переполнитесь, а если десятичное число будет меньше, чем int.MinValue, оно опустится.

Что происходит, когда вы находитесь под / переполнение? Одна из двух вещей. Если ваша сборка не проверена (т. Е. CLR не волнует, если вы это сделаете), ваше приложение продолжит работу после того, как значение превысит / понизит значение, но значение в int будет не тем, что вы ожидали. Это может привести к периодическим ошибкам и может быть трудно исправить. В конечном итоге ваше приложение окажется в неизвестном состоянии, что может привести к повреждению вашего приложения какими-либо важными данными, над которыми он работает. Не хорошо.

Если ваша сборка проверена (свойства-> build-> advanced-> проверка на арифметическое переполнение / недополнение или параметр / checked компилятора), ваш код сгенерирует исключение при возникновении недостаточного / переполнения. Это, вероятно, лучше, чем нет; однако по умолчанию для сборок не выполняется проверка на переполнение / переполнение.

Настоящий вопрос - «что ты пытаешься сделать?» Не зная ваших требований, никто не может сказать вам, что вы должны делать в этом случае, кроме очевидного: НЕ ДЕЛАЙТЕ ЭТОГО.

Если вам не все равно, ответы здесь действительны. Тем не менее, вы должны сообщить о своем понимании того, что может произойти переполнение и что это не имеет значения, оборачивая ваш приведенный код в непроверенный блок

unchecked
{
  // do your conversions that may underflow/overflow here
}

Таким образом, люди, идущие за вами, понимают, что вам все равно, и если в будущем кто-то изменит ваши сборки на / флажок, ваш код не будет неожиданно сломан.

Если все, что вы хотите сделать, это отбросить дробную часть числа, оставив неотъемлемую часть, вы можете использовать Math.Truncate.

decimal actual = 10.5M;
decimal expected = 10M;
Assert.AreEqual(expected, Math.Truncate(actual));

источник
3
Хотя я подозреваю, что они одинаковы, если ввод десятичный, мне удобнее использовать Decimal.Truncate, а не Math.Truncate, поскольку последний также принимает двойные значения и, следовательно, может быть усечен для уравнивания четных чисел. которые не являются основанием 10, в отличие от Decimal.Truncate, который является истинным усечением числа с основанием 10.
Брайан
7
Непроверенные контексты не применяются к десятичным числам; операции с десятичными числами будут вызывать OverflowExceptions независимо.
Дейв
46
int i = (int)d;

даст вам число, округленное в меньшую сторону.

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

int i = (int)Math.Round(d, MidpointRounding.ToEven);

В общем, вы можете привести между всеми числовыми типами в C #. Если нет информации, которая будет потеряна во время приведения, вы можете сделать это неявно:

int i = 10;
decimal d = i;

хотя вы можете сделать это явно, если хотите:

int i = 10;
decimal d = (decimal)i;

Тем не менее, если вы собираетесь потерять информацию через актерский состав, вы должны сделать это явно (чтобы показать, что вы знаете, что вы можете потерять информацию):

decimal d = 10.5M;
int i = (int)d;

Здесь вы теряете ".5". Это может быть хорошо, но вы должны четко заявить об этом и сделать явное приведение, чтобы показать, что вы можете потерять информацию.

ICR
источник
1
Вы на самом деле хотите, чтобы MidpointRounding.AwayFromZero, если вы хотите, чтобы> * .5 всегда округлялся, основываясь на моем опыте опробования приведенного выше кода, при просмотре примера вывода здесь: msdn.microsoft.com/en-us/library/…
Элайджа Лофгрен
@ElijahLofgren Это отчасти зависит: если вы делаете статистику, ToEvenследует предотвратить смещение статистики. Однако если вы работаете с платными предметами или деньгами, это AwayFromZeroкажется правильным выбором.
mbx
22
decimal d = 2;
int i = (int) d;

Это должно работать просто отлично.

luiscubal
источник
Осторожнее, при явном преобразовании информация может быть потеряна.
Федрус
21
При преобразовании из десятичного числа в int информация почти всегда будет потеряна, но я считаю, что в этом суть.
Дина
8

System.Decimalреализует IConvertableинтерфейс, который имеетToInt32() член.

Звонок System.Decimal.ToInt32()работает для вас?

Энди
источник
2
Из документации : «Этот API поддерживает инфраструктуру .NET Framework и не предназначен для использования непосредственно из вашего кода». Почему бы не использовать Convert.ToInt32?
Х. Уолпер
7

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

decimal d = 10.1m;
d += .5m;
int i = (int)d;

Еще уходит i=10, но

decimal d = 10.5m;
d += .5m;
int i = (int)d;

Собрался бы так, что i=11.

DeadlyBrad42
источник
5
Зачем делать это, когда есть Math.Floor и Math.Ceiling?
Badaro
В то время я был довольно новичком в C # и по какой-то причине я не осознавал, что эти функции существуют. Это на самом деле трюк, который я узнал из C / C ++, где он был, очевидно, более полезным.
DeadlyBrad42
1
Что если десятичное значение было, например, -9,3?
суперкат
6

Я предпочитаю использовать Math.Round , Math.Floor , Math.Ceiling или Math.Truncate чтобы явно установить режим округления в зависимости от ситуации.

Обратите внимание, что все они также возвращают Decimal - поскольку Decimal имеет больший диапазон значений, чем Int32, поэтому вам все равно придется приводить (и проверять наличие переполнения / потери значения).

 checked {
   int i = (int)Math.Floor(d);
 }
Марк Брекетт
источник
6

Округление десятичной дроби до ближайшего целого

decimal a ;
int b = (int)(a + 0.5m);

когда a = 49.9тогдаb = 50

когда a = 49.5тогдаb = 50

когда a = 49.4, то b = 49и т. д.

sleepwalkerfx
источник
0

Я считаю, что оператор приведения не работает, если у вас есть десятичное число в штучной упаковке (то есть десятичное значение внутри типа объекта). Convert.ToInt32 (десятичный как объект) прекрасно работает в этом случае.

Эта ситуация возникает при получении значений IDENTITY / AUTONUMBER из базы данных:

SqlCommand foo = new SqlCommand("INSERT INTO...; SELECT SCOPE_IDENTITY()", conn);
int ID = Convert.ToInt32(foo.ExecuteScalar());  // works
int ID = (int)foo.ExecuteScalar();              // throws InvalidCastException

См. 4.3.2 Распаковка конверсий

Timbo
источник
2
Добавим больше к нему для справки: это потому, что вы можете распаковать только тот же тип оригинала. Здесь SELECT SCOPE_IDENTITY()возвращает, numeric(38, 0)что переводит на decimal.NET. foo.ExecuteScalar()возвращает в decimalштучной упаковке, objectкоторый не может быть приведен непосредственно к int. (int)(decimal)foo.ExecuteScalar()или Convert.ToInt32(foo.ExecuteScalar())будет работать.
rageit
0

Кажется, что ни один ответ не имеет отношения к OverflowException / UnderflowException, возникающему при попытке преобразовать десятичное число, выходящее за пределы диапазона int.

int intValue = (int)Math.Max(int.MinValue, Math.Min(int.MaxValue, decimalValue));

Это решение вернет максимальное или минимальное возможное значение типа int, если десятичное значение находится вне диапазона int. Возможно, вы захотите добавить некоторые округления с Math.Round, Math.Ceiling или Math.Floor для случаев, когда значение находится внутри диапазона int.

Kapten-N
источник