Подтвердить что ты не робот

Лучший (безопасный) способ конвертировать из double в int

Мне интересно, как лучше всего преобразовать double в int. Безопасность выполнения - вот моя главная проблема здесь (это необязательно должен быть самым быстрым методом, но это было бы моей второстепенной задачей). Я оставил несколько вариантов, с которыми я могу поговорить ниже. Может ли кто-нибудь весить, на котором лучше всего практиковать? Какие-нибудь лучшие способы сделать это, что я не перечислял?

        double foo = 1;
        int bar;

        // Option 1
        bool parsed = Int32.TryParse(foo.ToString(), out bar);
        if (parsed)
        {
            //...
        }

        // Option 2
        bar = Convert.ToInt32(foo);

        // Option 3
        if (foo < Int32.MaxValue && foo > Int32.MinValue) { bar = (Int32)foo; }
4b9b3361

Ответ 1

Я думаю, что ваш лучший вариант будет делать:

checked
{
    try
    {
        int bar = (int)foo;
    }
    catch (OverflowException)
    {
     ...          
    }
}

Из таблицы явных числовых преобразований

Когда вы конвертируете значение типа double или float в целочисленный тип, значение усекается. Если полученное интегральное значение находится за пределами диапазон целевого значения, результат зависит от переполнения проверка контекста. В проверенном контексте OverflowException брошенный, в то время как в непроверенном контексте, результат является неопределенным значение типа назначения.

Примечание: Вариант 2 также выдает OverflowException при необходимости.

Ответ 2

Я предпочитаю вариант 2.

Одна вещь, которую вам нужно сделать, это проверить исключения, но чтобы подтвердить, что это сработало, так же, как вы проверяете "разобран" в опции 1:

try
{
    bar = Convert.ToInt32(foo); 
}
catch(OverflowException)
{
    // no can do!
{

Если вы преобразовали строку и т.д. вместо double, вместо этого вы можете получить "FormatException".

Edit

Я изначально сказал, что вариант 2 не особенно лучше, чем вариант 1, который указал @0xA3. Вариант 1 хуже, потому что он преобразуется в строку перед анализом на целое число, что означает, что он менее эффективен. Вы также не получаете OverflowException, если double находится за пределами целочисленного диапазона (который вы можете или не хотите), хотя в этом случае "разобран" будет False.

Ответ 3

Я понимаю, что это не совсем то, о чем просил OP, но эта информация может быть удобной.

Вот сравнение (из http://www.dotnetspider.com/resources/1812-Difference-among-Int-Parse-Convert-ToInt.aspx)

        string s1 = "1234";
        string s2 = "1234.65";
        string s3 = null;
        string s4 = "12345678901234567890123456789012345678901234567890";

        int result;
        bool success;

        result = Int32.Parse(s1);      // 1234
        result = Int32.Parse(s2);      // FormatException
        result = Int32.Parse(s3);      // ArgumentNullException
        result = Int32.Parse(s4);      // OverflowException

        result = Convert.ToInt32(s1);      // 1234
        result = Convert.ToInt32(s2);      // FormatException
        result = Convert.ToInt32(s3);      // 0
        result = Convert.ToInt32(s4);      // OverflowException

        success = Int32.TryParse(s1, out result);      // 1234
        success = Int32.TryParse(s2, out result);      // 0
        success = Int32.TryParse(s3, out result);      // 0
        success = Int32.TryParse(s4, out result);      // 0

Ответ 4

Опция 3a, не использующая исключения, всегда возвращает значение:

    Int32 Convert(Double d)
    {
        if (d <= (double)Int32.MinValue)
            return Int32.MinValue;
        else if (d >= (double)Int32.MaxValue)
            return Int32.MaxValue;
        else 
            return (Int32)d;
    }

Ответ 5

Я бы использовал второй вариант. Короткая, чистая и работает.

Вы также можете посмотреть класс BigInteger в .Net4, и вам не нужно будет проверять наличие переполнения.

double foo = 1;            
BigInteger bigint = new BigInteger(foo);

Ответ 6

Я всегда использую класс Convert, я считаю его очень элегантным, удобным и вы можете поймать определенные исключения, определенные в VS intellisense.

Ответ 7

Варианты (1) и (2) делают практически то же самое. Вариант (1) дает вам блок if (parsed), тогда как опция (2) выдает ошибку для любого double, который не представляется в виде int.

Опция (3) по существу такая же, как опция (2), за исключением того, что она имеет дополнительную проверку MinValue/MaxValue, которую другие не делают.

Вкратце: эти три части кода делают разные вещи. Вариант (3) выглядит наиболее надежным, поскольку он имеет дополнительную проверку диапазона.

Изменить: Во-вторых, используйте трюк @Ani checked - вы получаете бесплатную проверку диапазона.

Ответ 8

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

int ToInt(double foo)
{
    int result = (int)foo;
    if (foo != result)
        throw new ArgumentException()

    return result;
}

Это приведет к тому, что не будет выполнено неверное преобразование. Если ОК округлить до ближайшего целого числа, используйте Math.Round и проверьте, находится ли результат в пределах 0,5. Это гарантирует, что ваш метод не получит NaN или бесконечность.