将18-19位double值转换为long时出现数值偏差问题求助
18-19位整数型double转long精度丢失问题解决
我需要把18-19位、小数部分固定为.0的double类型值转换为long类型,但直接用longValue()方法转换会出现精度丢失,结果和预期不符。
示例输入
double val1 = 1000000000000007403.0; double val2 = 2223372036854774845.0;
测试代码
public static void main (String args[]){ double val1 = 1000000000000007403.0; // 输入值 double val2 = 2223372036854774845.0; // 输入值 Double double1 = Double.valueOf(val1); Double double2 = Double.valueOf(val2); long val1Long = double1.longValue(); long val2Long = double2.longValue(); System.out.println(val1Long); System.out.println(val2Long); }
结果对比
输出结果:
1000000000000007424、2223372036854774784
预期结果:
1000000000000007403、2223372036854774845
问题规律:当double值的有效数字超过14-15位时,就会出现这种精度丢失情况。
原因分析
double是64位浮点数,其尾数部分仅52位(加上隐含的1位共53位),对应十进制的有效数字最多只有15-17位。当你把18-19位的整数赋值给double时,double无法精确存储该数值,会自动近似为最接近的可表示值——这就是调试时看到的double值已经偏离原始输入的原因,后续转long自然得不到正确结果。
解决方案
从源头避免用double存储大整数
如果能控制输入传递方式,不要用double存储高精度整数,改用字符串或BigDecimal类型接收,可完整保留原始数值,这是最优解:// 字符串转long String val1Str = "1000000000000007403"; long val1Long = Long.parseLong(val1Str); // BigDecimal转long BigDecimal bdVal2 = new BigDecimal("2223372036854774845"); long val2Long = bdVal2.longValueExact();仅能拿到已有double值时的补救方法
若无法修改输入类型,可先将double转为字符串,去掉末尾的.0后再转long,但注意:这种方式只能恢复double存储的近似值,无法还原被double丢失的原始精度(因为double本身已存储错误值):double val1 = 1000000000000007403.0; String val1Str = Double.toString(val1).replace(".0", ""); long val1Long = Long.parseLong(val1Str);
内容的提问来源于stack exchange,提问作者Keshav Singh
相关产品推荐
相关产品推荐

