Best (safest) way to convert from double to int

谁说胖子不能爱 提交于 2020-07-03 01:51:14

问题


I'm curious as to the best way to convert a double to an int. Runtime safety is my primary concern here (it doesn't necessarily have to be the fastest method, but that would be my secondary concern). I've left a few options I can come up with below. Can anyone weigh in on which is best practice? Any better ways to accomplish this that I haven't listed?

        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; }

回答1:


I think your best option would be to do:

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

From Explicit Numeric Conversions Table

When you convert from a double or float value to an integral type, the value is truncated. If the resulting integral value is outside the range of the destination value, the result depends on the overflow checking context. In a checked context, an OverflowException is thrown, while in an unchecked context, the result is an unspecified value of the destination type.

Note: Option 2 also throws an OverflowExceptionwhen required.




回答2:


I prefer option 2.

One thing you need to do is check for exceptions though to confirm it worked, the same way you're checking 'parsed' in option 1:

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

If you were converting string etc instead of double, you might get a 'FormatException' instead.

Edit

I originally said option 2 wasn't particularly better than option 1, which @0xA3 pointed out was wrong. Option 1 is worse because it converts to a string before being parsed to an integer, which means it's less efficient. You also don't get an OverflowException if the double is outside the integer range (which you may or may not want) - although 'parsed' will be False in this case.




回答3:


I realize this is not quite what the OP was asking for, but this info could be handy.

Here is a comparison (from 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:


Option 3a not using exceptions, always returns a value:

    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:


I always use the Convert class, I find it very elegant, handy and you can catch specific exceptions defined in the VS intellisense.




回答6:


I would use option two. Short, clean and it works.

You could also look into the BigInteger class in .Net4, and you wouldn't have to check for overflow.

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



回答7:


If you really really need to find out if something went wrong, use a normal cast and check the result.

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

    return result;
}

This will make sure no invalid conversion is done. If it is OK to round to nearest integer, use Math.Round and check if result is within 0.5. This will make sure no NaN or infinity will get by your method.




回答8:


Options (1) and (2) do essentially the same thing. Option (1) gives you an if (parsed) block whereas option (2) throws an error for any double that's not representable as an int.

Option (3) is essentially the same as option (2) except it has an extra MinValue/MaxValue check which the others don't.

In summary: these three pieces of code do different things. Option (3) looks to be the most robust, in that it has an extra range check.

Edit: On second thoughts, use @Ani checked trick - you get the range check for free.



来源:https://stackoverflow.com/questions/3549179/best-safest-way-to-convert-from-double-to-int

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!