oracle binary_float

来源:互联网 发布:淘宝面包鞋豆豆鞋 编辑:程序博客网 时间:2024/06/06 01:21

我有一个表如下:

createtable A_TEST

(

  id_n  NUMBER,

  val_f BINARY_FLOAT,

  val_d BINARY_DOUBLE

);

 

// 插入一条数据

INSERTINTO A_TEST(ID_N, VAL_F,VAL_D) VALUES (0.10.10.1);

 

// 如出刚才的数据发现binary_float 显示不对

SELECT * FROM A_TEST;

 

// 用程序查询的结果是对的

ResultSet set = 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_floatbinary_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.62510进制)à 1111011.1012进制)à 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 {

        Todeimal t = new Todeimal();

        List<Integer> binary = t.toBinary(0.1D, 23);

        System.out.println();

        t.toDecimal(binary);

        t.toDecimal("00011001100110011001101",23);

   }

   

   publicvoidtoDecimal (String binary,intmax){

        doubleres = 0;

        intj = 0;

        for (inti=0; i<maxi++) {

           intbit = Integer.valueOf(String.valueOf(binary.charAt(i)));

           res += bit * Math.pow(2, --j);

        }

       

        System.out.println("四舍五入: " + res);

   }

   

   publicvoidtoDecimal (List<Integer> binary) {

        doubleres = 0;

        intj = 0;

        for (Integer b : binary) {

           res += b * Math.pow(2, --j);

        }

       

        System.out.println("不舍入: " + res);

   }

 

   publicList<Integer> toBinary(Double fintmax){

        if (f >= 1 || f<= 0)

            returnnull;

        List<Integer> list = newArrayList<Integer>();

       

 

        intbits = 0;

        while (true) {

            f = calc(flist);

            bits++;

            if (bits == 50) {

                System.out.println();

            }

            if (bits == max)

                break;

        }

        System.out.println("len: " + list.size());

        for (Integer i : list) {

            System.out.print(i);

        }

       

        returnlist;

       

   }

 

   privateDouble calc(Double f,List<Integer> list){

        if (f == 0 )

            return -1D;

        Double t = f * 2;

        if (t >= 1) {

            list.add(1);

            returnt - 1;

        } else {

            list.add(0);

            returnt;

        }

   }

 

}

 

 

通过上面的计算方法0.1存储数据库再取出来结果应该是:

select to_char(id_n),to_char(val_f), val_f, to_char(val_d), val_d

from A_TEST; 

binary_float: 1.00000001E-001

binary_double: 1.0000000000000001E-001

由于plsql 在显示两种类型时取值精度不一样就成了不同的显示效果

 

为了证明是显示精度的问题:

INSERTINTO A_TEST(ID_N, VAL_F,VAL_D)

VALUES (0.10.5, to_number(1.0000000000000101E-001))

 

同样在程序中查询的效果也是因为精度问题所以显示没有问题

 

 

0 0
原创粉丝点击