我有以下功能:
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为负数。那有什么问题?
答案 0 :(得分:4)
问题是你试图在double
中保存一个带有19个有效数字(十进制)的整数值,其中15-16 significant digits。
因此,无法在double
中准确表示该值。显然舍入会导致值在转换为long时溢出,使其成为负值。
您可以这样确认:
var convertedValue = checked((long)roundedValue);
如果您绝对必须处理这种情况,我建议使用decimal
而不是double,或者将小数点上的字符串(或您的语言环境中使用的任何内容)拆分并处理以这种方式舍入。< / p>
答案 1 :(得分:1)
检查originalValue
的类型。它的编译时类型是object
,但运行时的实际类型是什么?如果是盒装数字类型,则无需拨打.ToString()
,然后拨打TryParse
。最好直接拆箱到正确的类型(特别是如果它始终是相同的运行时类型),然后在必要时转换为另一种数字类型。
如果您通过long
向0x7FFFFFFFFFFFFFFF
发送包含许多数字的long.MaxValue
,例如double
与long
相同,请注意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;
...
}
否则,您可以在long
到double
转化时遗漏一些信息。