将对象转换为long

时间:2013-02-23 07:57:33

标签: c#

我有以下功能:

    public virtual long AsLong(object originalValue,long defaultValue)
    {
        double buffer = defaultValue;
        if (originalValue != null)
        {
            double result;
            var readValueIsconverted = double.TryParse(originalValue.ToString(), out result);
            if (readValueIsconverted)
                buffer = result;
        }

        var roundedValue = Math.Round(buffer, 0);
        var convertedValue = (long) roundedValue;
        return convertedValue;
    }

我使用了双倍以便转换为14.4! 我有以下失败的测试:

    [Fact]
    public void CanConvertLongMaxValue()
    {
        var cellValue = new Converter();
        const long longValue = 0x7FFFFFFFFFFFFFFF;
        var result = cellValue.AsLong(longValue, 12);

        Assert.Equal(longValue, result);

    } 

我已跟踪代码并且roundedValue为正数,但convertedValue为负数。那有什么问题?

3 个答案:

答案 0 :(得分:4)

问题是你试图在double中保存一个带有19个有效数字(十进制)的整数值,其中15-16 significant digits

因此,无法在double中准确表示该值。显然舍入会导致值在转换为long时溢出,使其成为负值。

您可以这样确认:

var convertedValue = checked((long)roundedValue);

如果您绝对必须处理这种情况,我建议使用decimal而不是double,或者将小数点上的字符串(或您的语言环境中使用的任何内容)拆分并处理以这种方式舍入。< / p>

答案 1 :(得分:1)

检查originalValue的类型。它的编译时类型是object,但运行时的实际类型是什么?如果是盒装数字类型,则无需拨打.ToString(),然后拨打TryParse。最好直接拆箱到正确的类型(特别是如果它始终是相同的运行时类型),然后在必要时转换为另一种数字类型。

如果您通过long0x7FFFFFFFFFFFFFFF发送包含许多数字的long.MaxValue,例如doublelong相同,请注意double精度比double高约10位。从技术上讲,这是因为long.MaxValue使用11位作为指数,但不必存储最高位。

double的值处,double的精度会发生变化,因为当我们传递2的幂时,指数会增加1。 long.MaxValue以下的double值的精度为1024.这意味着只能表示1024的整数倍。毫不奇怪,<{em> long.MaxValue以上的long值的精度为2048.当然,整数类型double的精度始终为1。

以下三个最近的long.MaxValue以及三个9.22337203685477'27'36 E+18 9.22337203685477'37'60 E+18 9.22337203685477'47'84 E+18 --- 9.22337203685477'58'08 E+18 <-- two to the 63rd power 9.22337203685477'78'56 E+18 9.22337203685477'99'04 E+18

long.MaxValue

9223372036854775807,即double转换为9.223372036854775808E+18时,最近的可表示为1.0 .ToString()太大。其.ToString("R")的字符串表示仅显示15位数,而'将显示17位数(我上面列表中的撇号double)。将`9.223372036854775808E+18 long转换回1.0时,我们会收到溢出异常,因为该数字ulong太大了。当然,您仍然可以将数字转换为{{1}},这应该会显示确切的值。

答案 2 :(得分:0)

如果首先提供的参数为long,则应检查:

public virtual long AsLong(object originalValue,long defaultValue)
{
    if(originalValue.GetType() == typeof(long))
        return (long) originalValue;

    double buffer = defaultValue;

    ...
}

否则,您可以在longdouble转化时遗漏一些信息。