返回信息流【jdk版本】
C:\Users\Administrator>java -version
java version "1.6.0_30"
Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
Java HotSpot(TM) Client VM (build 20.5-b03, mixed mode, sharing)
【代码】
public static void main(String[] args) {
double a = 15070.3;
double b = 7600.0;
double c = a - b;
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
【运行结果】
15070.3
7600.0
7470.299999999999
【问题】
计算结果为啥是 7470.299999999999 呢?
这是一条镜像帖。来源:北邮人论坛 / java / #47757同步于 2016/1/26
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
double计算,看不明白,请教!
truthman
2016/1/26镜像同步11 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
因为double的保存方式并不能精确保存0.3所以它保存了一个近似值。
所以一般判断double相等的代码都会用 abs(a-b)<10^-6的方式来。
【 在 truthman 的大作中提到: 】
: C:\Users\Administrator>java -version
: java version "1.6.0_30"
: Java(TM) SE Runtime Environment (build 1.6.0_30-b12)
: ...................
又想起了设计电梯,浮点数用等号判断的那个梗
【 在 aiquestion 的大作中提到: 】
: 因为double的保存方式并不能精确保存0.3所以它保存了一个近似值。
: 所以一般判断double相等的代码都会用 abs(a-b)<10^-6的方式来。
: 【 在 truthman 的大作中提到
: .........
【 在 iamluo 的大作中提到: 】
: 又想起了设计电梯,浮点数用等号判断的那个梗
想起来还是觉得好玩,真人真事。 http://bbs.byr.cn/#!article/Picture/2812786
哈哈,暴漫谁画的?太有才了!
【 在 nuanyangyang 的大作中提到: 】
:
: 【 在 iamluo 的大作中提到: 】
: : 又想起了设计电梯,浮点数用等号判断的那个梗
:
: 想起来还是觉得好玩,真人真事。 http://bbs.byr.cn/#!article/P
: .........
认真地回答一下吧:IEEE754的double型数的格式如下:
S EEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
64位二进制,第一位是符号位,0为正,1为负;之后11位是指数部分,之后52位是小数部分。
这个数表示S 1.FFFFFFFFF……FFF * 2^(EEEEEEEEEEE - 1023),即:底数是那一堆F前面加上“1.”;指数是那些E组成的二进制整数减去1023。
比如,24.0可以精确地表示为:0 10000000011 1000000000000000000000000000000000000000000000000000
其中,指数部分10000000011用十进制表示是1027;底数是1.1000000000000000000000000000000000000000000000000000,用十进制表示就是1.5。
所以这个数就是1.5 * 2^(1027 - 1023) = 1.5 ^ 2^4 = 1.5 * 16 = 24
但15070.3不能精确地用二进制小数表示,因为那个.3用十进制可以有限地表示,但用二进制是除不尽的,是二进制的循环小数。
所以,用IEEE754 double只能近似表示。最接近15070.3的能表示的数就是: 0 10000001100 1101011011110010011001100110011001100110011001100110
看到后面的循环小数1100 1100 1100……了吧
幸运的是,7600.0可以精确地表示: 0 10000001011 1101101100000000000000000000000000000000000000000000
试试做它们的减法。它们的指数只相差1。我们就把指数统一起来,这两个数的差就是:
( 1.1101011011110010011001100110011001100110011001100110
-0.11101101100000000000000000000000000000000000000000000) * 2^(1036-1023)
= 0.1110100101110010011001100110011001100110011001100110 * 2^13
= 1110100101110.010011001100110011001100110011001100110
约等于十进制的7470.299999999
用IEEE754 double表示这个数,就是
0 10000001011 1101001011100100110011001100110011001100110011001100
但和7470.3最接近的是
0 10000001011 1101001011100100110011001100110011001100110011001101
应该就是最后那个0和1的差别造成了打印出7470.2999999999吧。
拜读了!多谢。
【 在 nuanyangyang 的大作中提到: 】
: 认真地回答一下吧:IEEE754的double型数的格式如下:
: S EEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
: 64位二进制,第一位是符号位,0为正,1为负;之后11位是指数部分,之后52位是小数部分。
: ...................
想再请教个问题。这个实际是项目中遇到的问题,涉及到的实际是钱数的比较。那这咋比较啊?我就是用15070.3和另外两笔钱7600.0和7470.3两笔钱进行的比较。
【代码】
import java.util.ArrayList;
import java.util.List;
public class Test11 {
public static void main(String[] args) {
dealWithDetailList(15070.3);
}
private static void dealWithDetailList(double canVerifiAmount4Detail){
if(canVerifiAmount4Detail == 0) return;
List<Account> detailList = new ArrayList<Account>();
detailList.add(new Account(0.0,7600.0,2));
detailList.add(new Account(0.0,7470.3,2));
List<Account> needDealList = new ArrayList<Account>();
if(detailList.size()>0){
for(Account po:detailList){
double unVerificationAmount = po.getUnVerificationAmount();
double verificationAmount = po.getVerificationAmount();
if(unVerificationAmount == 0) continue;
if(unVerificationAmount <= canVerifiAmount4Detail){
verificationAmount = verificationAmount + unVerificationAmount;
po.setVerificationAmount(verificationAmount);
po.setStatusId(6);
canVerifiAmount4Detail = canVerifiAmount4Detail - unVerificationAmount;
needDealList.add(po);
if(canVerifiAmount4Detail == 0) break;
}
else{
verificationAmount = canVerifiAmount4Detail + verificationAmount;
po.setVerificationAmount(verificationAmount);
unVerificationAmount = unVerificationAmount - canVerifiAmount4Detail;
po.setStatusId(5);
needDealList.add(po);
break;
}
}
for(Account po:needDealList){
System.out.println("VerificationAmount-" + po.getVerificationAmount() + "-UnVerificationAmount-" + po.getUnVerificationAmount() + "-StatusId-" + po.getStatusId());
System.out.println("========================");
}
}
}
}
class Account{
private Double verificationAmount;
private Double unVerificationAmount;
private Integer statusId;
public Account(Double verificationAmount,Double unVerificationAmount,Integer statusId){
this.verificationAmount = verificationAmount;
this.unVerificationAmount = unVerificationAmount;
this.statusId = statusId;
}
public Double getVerificationAmount() {
return verificationAmount;
}
public void setVerificationAmount(Double verificationAmount) {
this.verificationAmount = verificationAmount;
}
public Double getUnVerificationAmount() {
return unVerificationAmount;
}
public void setUnVerificationAmount(Double unVerificationAmount) {
this.unVerificationAmount = unVerificationAmount;
}
public Integer getStatusId() {
return statusId;
}
public void setStatusId(Integer statusId) {
this.statusId = statusId;
}
}
【 在 nuanyangyang 的大作中提到: 】
: 认真地回答一下吧:IEEE754的double型数的格式如下:
: S EEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
: 64位二进制,第一位是符号位,0为正,1为负;之后11位是指数部分,之后52位是小数部分。
: ...................