/ 我有一个表如下:
createtableA_TEST
(
id_nNUMBER,
val_f BINARY_FLOAT,
val_d BINARY_DOUBLE
);
//插入一条数据
INSERTINTOA_TEST(ID_N, VAL_F,VAL_D)VALUES(0.1,0.1,0.1);
//如出刚才的数据发现binary_float显示不对
SELECT*FROMA_TEST;
// 用程序查询的结果是对的
ResultSetset=oracle_stmt
.executeQuery("select id_n, val_f, val_d from A_TEST");
while(set.next()) {
System.out.println(set.getString(1) +", "
+set.getFloat(2)+", "
+set.getDouble(3));
}
//程序查询的返回值是这样的
// .1, 0.1, 0.1
先了解下binary_float与binary_double 的内存存储方式:
http://blog.csdn.net/yidian815/article/details/12912661
binary_float 4字节 32位:
符号位S(1位)指数位E(8位)尾数位M(23位)
binary_double 8 字节 64位
符号位S(1位)指数位E(11位)尾数位M(52位)
与浮点数对应数学值计算方法为:v=(-1)^s*M*2^E.
为了便于比较两个浮点数的大小,指数部分采用无符号整数来存储,但是为了解决指数为负数的情况,IEEE 754规定,指数域的存储值为实际值和指数偏移量之和,指数偏移量的计算方法为2^(e-1) - 1
指数E(存储值) = V(实际值) + 2^(e-1) – 1(e为指数位数)
如E(存储值) 129,那么V(实际值) = 129 – 2 ^ (8-1) -1 = 2
例子:
123.625(10进制)à1111011.101(2进制)à1.111011101*2^6。
将1.111011101去除首部的1(任何二进制转换为科学计数法后,其整数部分必为1(尾数域范围为【1-2)),因此可以在尾数域中忽略该位,以便存储更多的数据
M = 1.111011101à111011101à11101110100000000000000(填充0)
S = 0
E = 10000101
按照相反的过程,我们可以推倒出0 10000101 11101110100000000000000à
0 134 11101110100000000000000à
0 6 1.111011101à1.111011101*2^6à123.625
根据上面的理论0.1(十进制)à0.0001 1001 1001 1001 10011001 ……
十进制小数转二进制小数使用乘2取整数法:
0.1*2=0.2整数为:0
0.2*2=0.4整数为:0
0.4*2=0.8整数为:0
0.8*2=1.6整数为:1
0.6*2=1.2整数为:1
0.2*2=0.4 …
二进制小数转十进制小数:
0.abcd = a *2^-1 + b * 2^-2 + c * 2^-3 …..
java代码实现二进制与十进制相互转换:
publicclassTodeimal {
publicstaticvoidmain(String[]args)throwsException {
Todeimalt=newTodeimal();
Listbinary=t.toBinary(0.1D, 23);
System.out.println();
t.toDecimal(binary);
t.toDecimal("00011001100110011001101",23);
}
publicvoidtoDecimal (Stringbinary,intmax){
doubleres= 0;
intj= 0;
for(inti=0;i
intbit= Integer.valueOf(String.valueOf(binary.charAt(i)));
res+=bit* Math.pow(2, --j);
}
System.out.println("四舍五入: "+res);
}
publicvoidtoDecimal (Listbinary) {
doubleres= 0;
intj= 0;
for(Integerb:binary) {
res+=b* Math.pow(2, --j);
}
System.out.println("不舍入: "+res);
}
publicList toBinary(Doublef,intmax){
if(f>= 1 ||f<= 0)
returnnull;
Listlist=newArrayList();
intbits= 0;
while(true) {
f= calc(f,list);
bits++;
if(bits== 50) {
System.out.println();
}
if(bits==max)
break;
}
System.out.println("len: "+list.size());
for(Integeri:list) {
System.out.print(i);
}
returnlist;
}
privateDouble calc(Doublef,Listlist){
if(f== 0 )
return-1D;
Doublet=f* 2;
if(t>= 1) {
list.add(1);
returnt- 1;
}else{
list.add(0);
returnt;
}
}
}
通过上面的计算方法把0.1存储数据库再取出来结果应该是:
selectto_char(id_n),to_char(val_f), val_f, to_char(val_d), val_d
fromA_TEST;
binary_float: 1.00000001E-001
binary_double: 1.0000000000000001E-001
由于plsql在显示两种类型时取值精度不一样就成了不同的显示效果
为了证明是显示精度的问题:
INSERTINTOA_TEST(ID_N, VAL_F,VAL_D)
VALUES(0.1,0.5, to_number(1.0000000000000101E-001))
同样在程序中查询的效果也是因为精度问题所以显示没有问题