public class Test
{
public static void main(String[] args)
{
double x = 0.01;
double y = 0.09;
System.out.println(x + y);
}
}为什么输出结果是0.09999999999999999而不是0.1啊?
奇怪的是当x,y改为float后,结果就等于0.1了,
更奇怪的是,如果把x,y分别改为float的0.01和0.04,在相加,结果居然是0.049999997,
这种浮点运算不精确的背后原理到底是什么呢?更加怪异的是,这段代码放到C#中运行,出来的结果却是0.1 class Test
{
static void Main()
{
double x = 0.01;
double y = 0.09;
Console.WriteLine(x + y);
Console.ReadKey();
}
}
{
public static void main(String[] args)
{
double x = 0.01;
double y = 0.09;
System.out.println(x + y);
}
}为什么输出结果是0.09999999999999999而不是0.1啊?
奇怪的是当x,y改为float后,结果就等于0.1了,
更奇怪的是,如果把x,y分别改为float的0.01和0.04,在相加,结果居然是0.049999997,
这种浮点运算不精确的背后原理到底是什么呢?更加怪异的是,这段代码放到C#中运行,出来的结果却是0.1 class Test
{
static void Main()
{
double x = 0.01;
double y = 0.09;
Console.WriteLine(x + y);
Console.ReadKey();
}
}
解决方案 »
- 120急救!!!servlet连接mysql的错误
- 关于参数返回的问题,返回一个数组后,怎么限制修改数组的值,
- 怎么让矩形顺着我画的线溜下来
- 不用dispatcher如何转发request
- 请问如何捕捉windows 鼠标拖动文件事件
- JComboBox第一次选取时为什么没有响应itemStateChanged事件。
- Applet to Swing (100分)
- 求大神解答mysql时间函数问题~真心很难
- 安装JDK进度条到48%就不再动了,请高人解答
- Java初学者求助 自动装箱和拆箱问题
- 如何防止一个按钮,连续点击,多次提交??
- classLoader.getResources怎么不能返回资源?
//java是一门很怪异的语言
System.out.println(1.0/0);//Infinity
System.out.println(1/0);// java.lang.ArithmeticException:
The details of proper input conversion from a Unicode string representation of a floating-point number to the internal IEEE 754 binary floating-point representation are described for the methods valueOf of class Float and class Double of the package java.lang.
原因
大体说下,float的0.1二进制形式是001111011 10011001100110011001101,根据符号位换算为10进制表达的值精确应该是这样计算 110011001100110011001101乘以2的负27次方,实际值是0.100000001490116119384765625
这样就产生了实际误差
这个误差对我们生活小打小闹没啥影响,但是对科学计算和银行这样的应用或者领域是致命的,因此要用Java银行以及科学计算会用java.math.BigDecimal提高精度,否则后果极其严重。参考我曾经回答过的CSDN帖子http://topic.csdn.net/u/20110804/00/15380122-33a1-474a-9b7f-3e90a000f0a8.html
public class DoubleClass{
public static void main(String[] args){
double x = 0.09;
double y = 0.01;
System.out.println((float)(x + y));
}
}
这里不详细解释,LZ可查阅相关资料
有几个知识点:
1.计算机中浮点数的基数是2.
2.指数部分有偏移量(float为127, double为1023)
3.规格化的表示小数点左边一定为1.(二进制数)
4.float类型 符号位占1位,指数部分占8位,尾数占23位(因为规格化表示,小数点左边一定为1,所以实际有24位精度)
5.double类型 符号位占1位,指数部分占11位,尾数占52位(因为规格化表示,小数点左边一定为1,所以实际有53位精度)看一个例子float 0.6吧:
第一步,把十进制转2进制:
0.6的二进制表示(乘2取整,顺序表示):
.1001 1001 1001 1001 1001 1001 1001 ... 无限循环下去。第二步,计算尾数部分:
把.1001 1001 1001 1001 1001 1001 1001 ...规格化表示(小数点移到第一个非0书右边)就是:
1.001 1001 1001 1001 1001 1001 1001 ...,右移了1位。
由于规格化表示的数小数点左边一定为1,把这个1舍弃,并保留float尾数能表示的23位,最终尾数部分是:
001 1001 1001 1001 1001 1001第三步,计算指数部分:
由于计算尾数时右移了1位,相当于乘以2的负1次,所以指数为-1,加上float偏移量127,最后指数为126,
二进制表示为 0111 1110第四步,符号部分:
0.6为正数,符号位为0最终0.6在计算机中的表示就是: 符号位 指数 尾数
0 0111 1110 001 1001 1001 1001 1001 1001
--------------------------------------------------------------
我们再从这个2进制来计算10进制数:(2的指数次 * 尾数)
符号位0--> 为正
指数 0111 1110:为126, 减去偏移量127,结果为-1.
尾数 001 1001 1001 1001 1001 1001: 规格化的时候小数点左边人掉了一个1,现在加上:
1.001 1001 1001 1001 1001 1001,转为10进制就是:
1*2^0 + 1*2^-3 + 1*2^-4 + .....= 1.19999992847442626953125
1.19999992847442626953125 * 2^-1 = 0.599999964237213134765625
所以最终结果是一个无限接近于0.6而不能精确表示0.6 --------------------------------------
其实我在这个帖子已经回复过了