出现的问题:
一般来说,高字节数往低字节数转换时会出现精度丢失的问题,而低字节数往高字节转换时不会出现精度丢失的问题
但是也有例外:
@Test
public void test() {
float f = 12.12325f;
double d = f;
System.out.println(d);
}
预期结果:12.12325
实际结果:12.123250007629395
结论:出现了精度丢失
原因:
对于这个现象,我百度,goole之后都没有给出一个比较详细的解释,有哪位知道麻烦告诉我啊,谢谢。
解决方法:
先将float类型的数据转换为String类型,在转换为double类型
@Test
public void test() {
float f = 12.12325f;
double d = f;
System.out.println(Double.valueOf(String.valueOf(f)));
}
运算结果:12.12325
BigDecimal:
再查找上面问题时发现了 BigDecimal
百度百科的解释:
Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。 [1]
从上面知道 BigDecimal 是比 float 和 double 表示范围更大的一种数据类型
示例:
@Test
public void test5(){
float f = 0.11F;
double d = 4324323.12;
System.out.println(d+f);
}
预期结果:4324323.23
实际结果:4324323.2299999995
解决方法一(未解决问题):
使用 BigDecimal 的 BigDecimal(double val)和 BigDecimal(float val)方法
@Test
public void test6(){
float f = 0.11F;
double d = 4324323.12;
BigDecimal bd1 = new BigDecimal(f);
BigDecimal bd2 = new BigDecimal(d);
System.out.println(bd1.add(bd2));
}
运算结果:4324323.229999999515712261199951171875
发现并没有解决问题,仍然出现了精度丢失的问题
解决方法二:
使用 BigDecimal 的 BigDecimal(String val)方法
@Test
public void test4(){
float f = 0.11F;
double d = 4324323.12;
BigDecimal bd1 = new BigDecimal(String.valueOf(f));
BigDecimal bd2 = new BigDecimal(String.valueOf(d));
System.out.println(bd1.add(bd2));
}
运算结果:4324323.23
发现这次没有出现丢失精度的问题
Utils:
如果每次进行浮点数运算时都将浮点数先转为String类型,在进行运算,会比较繁琐,这里有大神写的工具类可以直接拿来用:
package com.util;
import java.math.BigDecimal;
/**
* 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精确的浮点数运算,包括加減乘除和四捨五入。
*/
public class Arith {
//默认吃吃饭运算精度
private static final int DEF_DIV_SCALE = 10;
//这个类不能实例化
private Arith() {
}
/**
* 提供精确的加法运算
*
* @param v1
* 被加数
* @param v2
* 加数
* @return 两个参数的和
*/
public static double add(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
/**
* 提供精确的减法运算
* @param v1
* 被減数
* @param v2
* 減数
* @return两个参数的差
*/
public static double sub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
/**
* 提供精确的乘法运算
*
* @param v1
* 被乘数
* @param v2
* 乘数
* @return 两个参数的积
*/
public static double mul(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
/**
* 提供(相对)精确的除非运算,当发生除不尽的情况时,精确到小数点以后10位,以后的数字四舍五入
* @param v1
* 被除數
* @param v2
* 除數
* @return 兩個參數的商
*/
public static double div(double v1, double v2) {
return div(v1, v2, DEF_DIV_SCALE);
}
/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入
* @param v1
* 被除數
* @param v2
* 除數
* @param scale
* 表示表示需要精確到小數點以後位数。
* @return 兩個參數的商
*/
public static double div(double v1, double v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供精確的小數位四捨五入處理。
* 提供精确的小数位四舍五入处理
*
* @param v
* 需要四捨五入的數位
* @param scale
* 小數點後保留幾位
* @return 四捨五入後的結果
*/
public static double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1");
return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
}
本人才疏学浅,有写的不对或不到的地方希望各位指出