3

我有以下功能:

    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,我使用了 double !我有以下失败的测试:

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

        Assert.Equal(longValue, result);

    } 

我跟踪了代码,roundedValue 是正数,但 convertValue 是负数。那么问题是什么?

4

3 回答 3

4

问题是您试图在double具有15-16 位有效数字的 a 中保存一个具有 19 位有效数字(十进制)的整数值。

因此,不可能在double. 显然,舍入会导致值在转换为 long 时溢出,使其成为负值。

您可以这样确认:

var convertedValue = checked((long)roundedValue);

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

于 2013-02-23T08:34:32.560 回答
1

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

如果您通过a 发送long具有许多数字的 a,例如0x7FFFFFFFFFFFFFFF与 相同,请注意 a的精度比 a 高大约 10 位。从技术上讲,这是因为 a使用 11 位作为指数,但不必存储最高有效位。long.MaxValuedoublelongdoubledouble

在 的值处long.MaxValue,a 的精度会发生double变化,因为当我们通过 2 的幂时,指数会增加 1。double下面的值long.MaxValue的精度为 1024。这意味着只能表示 1024 的整数倍。毫不奇怪,上面double的值具有 2048 的精度。当然,整数类型的精度始终是 1。 long.MaxValuelong

以下是最近的三个double下和三个上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时,即9223372036854775807double最接近的可表示9.223372036854775808E+181.0太大。它的字符串表示.ToString()将仅显示 15 位数字,而.ToString("R")将显示 17 位数字(我上面列表中的撇号')。将double `9.223372036854775808E+18back转换为 时,由于数字太大long,我们得到了溢出异常。1.0当然,您仍然可以将数字转换为ulong,这应该会显示确切的值。

于 2013-02-23T16:46:50.620 回答
0

您应该检查是否long首先提供了参数:

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

    double buffer = defaultValue;

    ...
}

否则,您可能会丢失一些有关long转换的信息double

于 2013-02-23T08:37:26.487 回答