Преобразование double в int в C #

103

В нашем коде есть двойник, который нам нужно преобразовать в int.

double score = 8.6;
int i1 = Convert.ToInt32(score);
int i2 = (int)score;

Кто-нибудь может объяснить мне, почему i1 != i2?

В результате я получаю следующее: i1 = 9и i2 = 8.

Воутер Доржело
источник
5
Math.Truncate(score)более явно выраженное намерение, чем(int)score
Lu55
3
Но Math.Truncate возвращает двойное или десятичное, а не int
Sergioet

Ответы:

165

Потому что Convert.ToInt32раундов:

Возвращаемое значение: округлено до ближайшего 32-разрядного целого числа со знаком. Если значение находится посередине между двумя целыми числами, возвращается четное число; то есть 4,5 преобразуется в 4, а 5,5 преобразуется в 6.

... пока приведение обрезается :

При преобразовании значения double или float в целочисленный тип значение усекается.

Обновление: см. Комментарий Джеппе Стига Нильсена ниже для дополнительных различий (которые, однако, не вступают в игру, если scoreэто действительное число, как здесь).

Джон
источник
6
Ваша ссылка на самом деле объясняет это лучше всего, и это не так просто, как round vs truncate: Type: System.Int32 value, округленное до ближайшего 32-битного целого числа со знаком. Если значение находится посередине между двумя целыми числами, возвращается четное число; то есть 4.5 конвертируется в 4, а 5.5 конвертируется в 6.
ericosg
@ericosg: Да, что бы маскировать разницу , если scoreбыли 8.5вместо 8.6. Я обновил ответ, включив цитаты. Спасибо за вклад.
Джон
5
И если scoreравно NaNили бесконечность или конечное значение, но вне диапазона Int32, то Convert.ToInt32будет выдано исключение. Cast вернет int, но вы не узнаете, какой из них (в моей реализации это Int32.MinValue), потому что вы находитесь в uncheckedконтексте. (Если вы находитесь в checkedконтексте, актерский состав также вызовет исключение в этих случаях.)
Йеппе Стиг Нильсен
@JeppeStigNielsen: Спасибо за ввод, я обновил ответ, чтобы упомянуть и об этом.
Джон
Ницца. Но я думаю, что Doubleтиповое число 10000000000.6(десять миллиардов целых шесть десятых) - это «реальное» число. Использование приведения к intэтому даст странный результат (если вы не находитесь в checkedконтексте, но, вероятно, это не так).
Йеппе Стиг Нильсен
13

Приведение игнорирует все, что находится после десятичной точки, поэтому 8,6 становится 8.

Convert.ToInt32(8.6) - это безопасный способ обеспечить округление двойного числа до ближайшего целого числа, в данном случае 9.

невменяемость
источник
1
Бонусный вопрос - что произойдет, если значение double слишком велико, чтобы вставить его в int ? Т.е. если он выше int.MAX_VAL ?
Конрад Вильтерстен,
1
@KonradViltersten Выдает исключение Значение слишком велико или слишком мало для Int32.
Vamsi
11

вы можете округлить свой дубль и бросить его:

(int)Math.Round(myDouble);
Дэвид
источник
4
теперь вопрос как сделать i1 == i2. Вопрос был в том, почему они не равны. Проголосовали против.
Adam
5

В приведенном примере ваше десятичное число - 8,6 . Если бы это было 8.5 или 9.5, утверждение i1 == i2 могло бы быть правдой. Фактически, это было бы верно для 8,5 и ложно для 9,5.

Пояснение:

Независимо от десятичной части, второй оператор int i2 = (int)scoreотбросит десятичную часть и просто вернет вам целую часть. Это довольно опасная вещь, так как может произойти потеря данных.

Теперь для первого утверждения могут произойти две вещи. Если десятичная часть равна 5, то есть наполовину, необходимо принять решение. Мы округляем в большую или меньшую сторону? В C # класс Convert реализует банковское округление. См. Этот ответ для более глубокого объяснения. Проще говоря, если число четное, округлить в меньшую сторону, если число нечетное - округлить в большую сторону.

Например, рассмотрите:

        double score = 8.5;
        int i1 = Convert.ToInt32(score); // 8
        int i2 = (int)score;             // 8

        score += 1;
        i1 = Convert.ToInt32(score);     // 10
        i2 = (int)score;                 // 9
Евджан Мустафа
источник
2

ToInt32 раундов. Приведение к int просто отбрасывает нецелочисленный компонент.


источник