黑马程序员技术交流社区
标题:
double转float的的三个问题
[打印本页]
作者:
荣凯旋
时间:
2012-1-18 17:43
标题:
double转float的的三个问题
本帖最后由 荣凯旋 于 2012-1-20 15:37 编辑
为什么double转float不会出现数据误差,而float转double却误差如此之大?
class Text
{
public static void main(String[] args)
{
float f = 0.15f;
double d = f;
System.out.println("d="+d);//输出结果:0.15000000596046448
double d1 = 0.15;
float f1 = (float)d1;
System.out.println("f1="+f1);//输出结果:0.15
double d2 = 0.15 + 0.15f;
System.out.println("d2="+d2);//输出结果:0.300000059604645
}
}
为什么结果会是这样呢?
如何避免这样的问题发生?
如何让float转double能得到实际的数据?
3个问题请大家讲解
作者:
房宝彬
时间:
2012-1-18 17:50
本帖最后由 房宝彬 于 2012-1-18 18:08 编辑
{:soso__6235880048239246314_3:}精度不一样,我先研究研究。
作者:
张伟~
时间:
2012-1-18 18:39
首先,float是4个字节,double是8个字节,flaot转double时需要补位
然后一转就成那样了,至于为什么是0.15000000596046448 之类,这貌似涉及到float和double这两者的内在构造问题了。
楼主想深入的了解下,还是自己去百度下吧
作者:
孙玉伟
时间:
2012-1-18 19:11
当将低级别的值赋给高级别变量时,系统自动完成转换。
例如:
int i=52;
float x;
x=i;//将int型52转换成float型52.0,结果x获取的值是52.0。
将高级别的值赋给低级别变量时,必须进行强制转换。强制类型转换格式:
(类型标识符)待转换的值
例如:
int i;
i=(int)26L;//将long类型值26转换成int类型26,结果i获得int类型值26;
作者:
荣凯旋
时间:
2012-1-19 15:24
怎么没有人3个问题都能回答全的嘛?? 快过年了上的人少啦呀
作者:
沈样
时间:
2012-1-19 18:49
这是因为字节的原因,低来高转换不会丢失,高向低会被 截断,所以会出现上面的情况
作者:
许涛
时间:
2012-1-19 20:48
本帖最后由 许涛 于 2012-1-19 20:50 编辑
float为4个字节,double为8个字节,float转化为double时精度被扩充了,所以出现上述结果
建议使用 BigDecimal,先将float类型数据包装成BigDecimal数据,然后调用其floatValue()方法
代码如下:
import java.math.*;
class Text
{
public static void main(String[] args)
{
float f = 0.15f;
BigDecimal a = new BigDecimal(String.valueOf(f));
double d = a.doubleValue();
System.out.println("d="+d);
}
}
作者:
荣凯旋
时间:
2012-1-20 11:59
本帖最后由 荣凯旋 于 2012-1-20 14:22 编辑
class Text
{
public static void main(String[] args)
{
float f = 0.15f;
double d = f;
System.out.println("d="+d);//输出结果:0.15000000596046448 同一个数弄俩不同类型!!类型提升,位数有4个字节变8个字节,有小数点后的7为升到15位
double d1 = 0.15;
float f1 = (float)d1;
System.out.println("f1="+f1);//输出结果:0.15 同一个数弄俩不同类型!强制转换,有8个字节强制变4个字节,丢弃后4个字节~所以值是这个~有小数点后的15为变7位,后面都是0就舍弃啦
double d2 = 1.15 + 1.15f;
System.out.println("d2="+d2);//输出结果:2.299999976158142 类型不同,小数点后面的位数相同
double d3 = 1.15 + 1.25f;
System.out.println("d3="+d3);//输出结果: 类型不同,小数点的位数是不同 结果:相加2.4
float f2 = 1.25f +1.15f;
System.out.println("f2="+f2);//输出结果:类型相同 小数点后数字不同 结果是2.4
}
}
有此结果的去一个新问题! 为什么 也就是 d2 d3 的值得问题~~没搞清楚 为什么小数点位后面的数相同,相加就有会出现精度问题呢??
刚搞懂一个问题 新问题有出现啦~~大家想想为啥呀???是不是我咱牛角尖啦??问题出在那里呢??
作者:
黄秋
时间:
2012-1-20 17:29
本帖最后由 黄秋 于 2012-1-20 17:47 编辑
double转float,会丢失精度,这不难理解,因float 比double 精度低,详见“java float double精度为什么会丢失?”http://blog.csdn.net/abing37/article/details/5332798,但float、double类型计算出来的结果,为什么会不准确呢?这就有了LZ的三个问题:
1. 为什么结果会是这样呢?
2. 如何避免这样的问题发生?
3. 如何让float转double能得到实际的数据?
问题一:为什么结果会是这样呢?
关键一点是,
十进制的小数,二进制表示有时不够精确
。浮点数值没办法用十进制来精确表示的原因要归咎于CPU表示浮点数的方法。整数可以用二进制精确表示 ,但小数就不一定了,原因在于浮点数由两部分组成:指数和尾数。
浮点数的值实际上是由一个特定的数学公式计算得到的。精度损失会在任何操作系统和编程环境中遇到
,JAVA也难免。举个例子,0.9表示成二进制数:
0.9*2=1.8 取整数部分 1
0.8(1.8的小数部分)*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 1
0.2*2=0.4 取整数部分 0
0.4*2=0.8 取整数部分 0
0.8*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 0
......... 0.9二进制表示为(从上往下): 1100100100100......
注意:上面的计算过程循环了,也就是说*2永远不可能消灭小数部分,这样算法将无限下去。很显然,小数的二进制表示有时是不可能精确的 。其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/10。
如计算12.0f-11.9f,将一个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位。
11.9f 转为二进制:
(1) 将11.9化为二进制后
大约是(主要是0.9无法准确表示)
" 1011. 1110011001100110011001100..."。
(2) 将小数点左移三位到第一个有效位右侧: "1. 011 11100110011001100110 "。 保证有效位数24位,
右侧多余的截取,误差就在这里产生了
。
步骤3~6,略。
11.9f 为: 0 1 0000010 011 11100110011001100110
计算12.0f-11.9f:
12.0f 为: 0 1 0000010 10000000000000000000000
(两浮点数进行加减,首先要看两数的 指数位 是否相同,即小数点位置是否对齐。若相同,表示小数点是对齐的,就可以进行尾数的加减运算。若两数阶码不同,必须先对阶--使两数的阶码相同)12.0f 与 11.9f 指数位完全相同,只要对有效数位进行减法即可:
12.0f-11.9f 结果: 0 1 0000010 00000011001100110011010
将结果还原为十进制: 0.000 11001100110011010= 0.10000038
问题二、三:如何避免这样的问题发生,如何能得到实际的数据?
float和double只适合做科学计算或者是工程计算,在商业计算中我们应用java.math.BigDecimal,注意一点,BigDecimal要用String来够造。我们可以下载工具类Arith,或自己调用BigDecimal,例如:
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();
}
复制代码
作者:
荣凯旋
时间:
2012-1-20 18:19
你的回答可以说是最经典的回答~谢谢啦~
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2