问题:将一个String类型的小数拆分为整数部分和小数部分,如9.9拆分为9和0.9

1.将小数的整数和小数部分拆分开

public float numberSub(String totalMoney){
float moneyFloat=Float.parseFloat(totalMoney);
System.out.println("moneyFloat="+moneyFloat);
int moneyInteger=(int) moneyFloat;
System.out.println("moneyInteger="+moneyInteger);
float moneyDecimal=moneyFloat-moneyInteger;
System.out.println("moneyDecimal="+moneyDecimal);
float result=this.sub(moneyFloat, moneyInteger);
return result;
}

上面这个方法里面,float-->int转化时直接丢弃小数部分,从而取得小数中的整数,而后作差得到小数部分,但是看下面输出:

2.浮点型表示一个小数的时候存在精度不准确的问题

原因:

首先我们要搞清楚下面两个问题:
() 十进制整数如何转化为二进制数
算法很简单。举个例子,11表示成二进制数:
/=5 余 /= 余 /= 余 /= 余 0结束 11二进制表示为(从下往上): 这里提一点:只要遇到除以后的结果为0了就结束了,大家想一想,所有的整数除以2是不是一定能够最终得到0。换句话说,所有的整数转变为二进制数的算法会不会无限循环下去呢?绝对不会,整数永远可以用二进制精确表示 ,但小数就不一定了。 () 十进制小数如何转化为二进制数
算法是乘以2直到没有了小数为止。举个例子,.9表示成二进制数
0.9*=1.8 取整数部分 0.8(.8的小数部分)*=1.6 取整数部分 0.6*=1.2 取整数部分 0.2*=0.4 取整数部分 0.4*=0.8 取整数部分 0.8*=1.6 取整数部分 0.6*=1.2 取整数部分 ......... .9二进制表示为(从上往下): ...... 注意:上面的计算过程循环了,也就是说*2永远不可能消灭小数部分,这样算法将无限下去。很显然,小数的二进制表示有时是不可能精确的 。其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/。这也就解释了为什么浮点型减法出现了精度丢失的问题。

3.验证

众所周知、 Java 的float型在内存中占4个字节。float的32个二进制位结构如下

float内存存储结构   

 4bytes          31                  30                29----23          22----0         

 表示       实数符号位      指数符号位        指数位          有效数位

 其中符号位1表示正,0表示负。有效位数位24位,其中一位是实数符号位。

将一个float型转化为内存存储格式的步骤为:

(1)先将这个实数的绝对值化为二进制格式,注意实数的整数部分和小数部分的二进制方法在上面已经探讨过了。 
     (2)将这个二进制格式实数的小数点左移或右移n位,直到小数点移动到第一个有效数字的右边。 
     (3)从小数点右边第一位开始数出二十三位数字放入第22到第0位。 
     (4)如果实数是正的,则在第31位放入“0”,否则放入“1”。 
     (5)如果n 是左移得到的,说明指数是正的,第30位放入“1”。如果n是右移得到的或n=0,则第30位放入“0”。 
     (6)如果n是左移得到的,则将n减去1后化为二进制,并在左边加“0”补足七位,放入第29到第23位。如果n是右移得到的或n=0,则将n化为二进制后在左边加“0”补足七位,再各位求反,再放入第29到第23位。

我们以数字8举例验证,float类型为8.0

1.将8.0转换为二进制之后是1000.0

2.将小数点左移三位到第一个有效位右侧1.0000(保证有效位数24位)得1.00000000000000000000000(只保留24位,多出的被截取掉了,从而引起了误差!)

3.这时已经有了二十四位有效数字,将最左边一位“1”去掉,得到0000000000000000000000共23位,将它放入float存储结构的第22到第0位。

4.因为8.0是正数,因此在第31位实数符号位放入“0”。

5.由于我们把小数点左移,因此在第30位指数符号位放入“1”。

6.因为我们是把小数点左移3位,因此将3减去1得2,化为二进制并补足7位得到0000010,放入第29到第23位。

最后得到0 1 0000010 0000000000000000000000

代码中打印出来如下:

public void testJavaDataType(){
int aint=;
float afloat=;
int fl=Float.floatToIntBits(afloat);
double adouble=;
long dl=Double.doubleToLongBits(adouble);
System.out.println("Int 8 :"+Integer.toBinaryString(aint));
System.out.println("Float 8 :"+Integer.toBinaryString(fl));
System.out.println("Double 8 :"+Long.toBinaryString(dl));
}

打印的时候如果是整数则第31位0默认不打印,篮框是第30位指数符号位,红框是指数位,蓝底是有效位数

很显然对于小数来说一个有限的23位有效位数是不足以精确表示一个小数的。

4.BigDecimal解决

public float sub(float a,float b){
BigDecimal bda=new BigDecimal(Float.toString(a));
BigDecimal bdb=new BigDecimal(String.valueOf(b));
return bda.subtract(bdb).floatValue();
}

5.利用String截取小数点来解决该问题

public float stringSub(String totalMoeny){
String[] strArray=totalMoeny.split("\\.");
if(strArray.length>=){
float a=Float.valueOf(strArray[]);
System.out.println(a);
float b=Float.parseFloat("0."+strArray[1]);
System.out.println(b);
return a-b;
}else{
return 0l;
}
}

参考文章:

http://blog.csdn.net/chencheng19912012/article/details/30072389

http://www.cnblogs.com/jym-sunshine/p/5853070.html

http://blog.csdn.net/tomcat_2014/article/details/51453988

java 将小数拆分为两部分+浮点型精度丢失问题的更多相关文章

  1. java 取小数点后两位 不四舍五入,怎么做

    java 取小数点后两位 不四舍五入,怎么做 正常版: //正常版: import java.text.DecimalFormat; import java.math.RoundingMode; De ...

  2. Java中String转换Double类型 Java小数点后留两位

    Java中String转换Double类型 double num1 = 0.0; String qq = "19.987"; num1 = Double.valueOf(qq.to ...

  3. 如何把Java的double类型变量保留两位小数

    已知 双精度标量 f,  如果想以字符串形式输出,小数点后保留2位,可直接通过C语言的输出格式,System.out.printf("%.2f", f), 达到目的. 如果想要先转 ...

  4. java取小数点后两位

    package com.yonyou.sud.algorithm; import java.math.BigDecimal;import java.text.DecimalFormat;/*** ja ...

  5. java 保留小数点后N位数(若干位),几种实现的方式总结

    import java.math.BigDecimal;import java.text.DecimalFormat;import java.text.NumberFormat;/** * java ...

  6. Java中产生随机数的两个方法

    Java中产生随机数的两个方法 一.利用random方法来生成Java随机数. 在Java语言中生成Java随机数相对来说比较简单,因为有一个现成的方法可以使用.在Math类中,Java语言提供了一个 ...

  7. Java页面中文编码要转换两次encodeURI

    1.js文件中使用encodeURI()方法. login_name = encodeURI(encodeURI(login_name)); 2.action中URLDecoder解码 loginNa ...

  8. 分列:将excel单元格的内容拆分为两列

    提要:处理excel数据时有时需要把单元格的内容拆分为两列,可能方便外部软件的链接,可能使数据显示更明晰等等,有人说直接剪切加粘贴不就可以了吗,但是有时数据过多,这样处理很不效率,网上搜索的方法说插入 ...

  9. Java中HashMap遍历的两种方式

    Java中HashMap遍历的两种方式 转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: ...

随机推荐

  1. Java去除所有非中文字符串

    "fdsfjasd阿斯顿飞机阿斯蒂芬,,,,,,,,....".replaceAll("[^\u4E00-\u9FA5]", "");

  2. A*寻路算法(曼哈顿距离)

    前一些天,在群有人问到A*算法的问题. 之前我已经有实现过,并将之放到github上(https://github.com/XJM2013/A_Star).有兴趣的能够下载下来看看. 这里上传了一个相 ...

  3. aar

    aar是一个类似于jar的文件格式.但是他们之间是有区别的.jar:仅仅包含class和清单文件,没有资源文件.aar:包含了class文件和资源文件.说白了就是Android的专属“jar” 将代码 ...

  4. UILabel 行间距设置

    NSMutableAttributedString * attributedString1 = [[NSMutableAttributedString alloc] initWithString:te ...

  5. [LeetCode] Maximum Subarray Sum

    Dynamic Programming There is a nice introduction to the DP algorithm in this Wikipedia article. The ...

  6. Vue基础-双向绑定:从 html 到 模板 到 渲染函数

    Vue 测试版本:Vue.js v2.5.13 在 Vue 中,可以利用 v-model 语法糖实现数据的双向绑定,例如: <div id="app"> <inp ...

  7. 各大网站CSS初始化代码集合

    css代码之所以初始化,是因为能尽量减少 各浏览器之间的兼容性问题! 腾讯QQ官网 样式初始化 body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fiel ...

  8. Python--进阶处理7

    # ====================第七章:函数========================= # 为了能让一个函数接受任意数量的位置参数,可以使用一个* 参数# 为了接受任意数量的关键字 ...

  9. Java关键字final、static总结

    对Java关键字Final和Static进行总结. 一.final        根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方 ...

  10. 干货 | 蚂蚁金服是如何实现经典服务化架构往 Service Mesh 方向的演进的?

    干货 | 蚂蚁金服是如何实现经典服务化架构往 Service Mesh 方向的演进的? https://www.sohu.com/a/235575064_99940985 干货 | 蚂蚁金服是如何实现 ...