public static void main(String[] args) {
Long a = 9800000000000005L;
// 这里我是用 double 当错参数
BigDecimal bigDecimal = new BigDecimal(a.doubleValue());
// 输出 9800000000000004; 精度缺失一位
System.out.println(bigDecimal);
}
long转double会损失精度
计算机的小数计算一定范围内精确,超过范围只能取近似值:计算机存储的浮点数受存储bit位数影响,只能保证一定范围内精准,超过bit范围的只能取近似值。
doulbe类型的数,不能用等号判定是否相等(或者是一定范围内可以)。因为两次同样的计算(除法)结果可能出现小数部分不同。甚至极端的时候,初始化两个小数时,都可能不相等(用数值和字符串分别初始化bigdecimal的小数就会不等)
java小数处理方法的经验总结:
(1)小数计算对精度无要求时,使用float节省时间。
(2)如果有精度要求,用BigDecimal类处理(初始化必须使用字符串,因为用数值初始化会得到近似值,不准确),然后设置保留位数和 舍入法(half_up四舍五入,half_even银行家,half_down向下取整)
(3)精度要求低时可转化为整数处理(集体统一扩大数量级):
乘以10的级数转化为整数处理,小数点右移几位,但整数值不要超过对应类型的取值范围。比如保留4位小数,可统一乘以10000,然后只保留整数计算结果,保留近位的话就多乘一位。
这种方式在RTB项目MDSP的算法核心模块中使用,几十万的投放量,用int或long就可以处理,更大范围的整数处理BigInteger。
为什么会出现这种情况呢?
那是因为在将十进制浮点数转换为二进制浮点数时,小数的二进制有时也是不可能精确的,就如同十进制不能准确表示1/3,二进制也无法准确表示1/10,而double类型存储尾数部分最多只能存储52位,于是,计算机在存储该浮点型数据时,便出现了精度丢失(1)。例如,11.9的内存存储大约为:1011. 1110011001100110011001100...
而在进行浮点类数据计算的时候,浮点参与计算,会左移或右移n位,直到小数点移动到第一个有效数字的右边。于是11.9在转化为二进制后 小数点左移3位,就得到1. 011 11100110011001100110(精度丢失2)
于是最终浮点型运算出现了精度丢失误差。
long转double也许会发生精度丢失。看转换值的大小。
long 需要64位表示精度,long 转 double 也可能出现精度丢失
long和double和别人转换以及和前端交互,都需要改成String或者通过String转换一下,否则都会有精度丢失的问题,这个是计算机位数的问题,逃避不了的
long转double会发生精度丢失