Monday, March 23, 2009

Oracle BINARY_FLOAT and BINARY_DOUBLE datatypes

Oracle introductes the BINARY_FLOAT and BINARY_DOUBLE datatypes since Oracle database 10g. These two datatypes are different from the NUMBER.

NUMBER stores data using decimal precision. BINARY floating-point numbers are stored
using binary precision (the digits 0 and 1).

BINARY_FLOAT is a 32-bit, single-precision floating-point number
datatype. BINARY_DOUBLE is a 64-bit, double-precision floating-point number
datatype. You can not specify a precision when you define a column with the BINARY_FLOAT or BINARY_DOUBLE datatype.

For example,
Create table t1
(f1 number,
f2 varchar2(20),
f3 binary_float(20));
f3 binary_float(20))
*
ERROR at line 4:ORA-00907: missing right parenthesis

After removing the precision from the create table statement, it can create table successfully.
Create table t1
(f1 number,
f2 varchar2(20),
f3 binary_float);
table created.

There are some special values for the BINARY_FLOAT/BINARY_DOUBLE datatypes.

BINARY_FLOAT_NAN A value of type BINARY_FLOAT for Not a Number
BINARY_DOUBLE_NAN A value of type BINARY_DOUBLE for Not a Number
BINARY_FLOAT_INFINITY A value of type BINARY_FLOAT for positive infinity(+∞)
BINARY_DOUBLE_INFINITY A value of type BINARY_DOUBLE for positive infinity(+∞)

Let's insert some rows using these special literal values.

insert into t1 values (1, 'string one', 1234567.89103245678);
insert into t1 values (2, '234.5678', BINARY_FLOAT_INFINITY);
insert into t1 values (3, 'string two', null);
insert into t1 values (4, '654.213', BINARY_FLOAT_NAN);
insert into t1 values (5, 'string three', -BINARY_FLOAT_INFINITY);
commit;

SQL> select * from t1;
F1 F2 F3
---------- -------------------- ----------
1 string one 1.235E+006
2 234.5678 Inf
3 string two
4 654.213 Nan
5 string three -Inf

Now, we have 5 rows.
Note: We use the -BINARY_FLOAT_INFINITY for the negative infinity(-∞).

You can test not a number using IS [NOT] NAN in the WHERE clause. But this is only working with the BINARY_FLOAT ot BINARY_DOUBLE datatype.

select * from t1 where f2 is nan;
select * from t1 where f2 is nan
*
ERROR at line 1:ORA-01722: invalid number

This is because f2 is not a BINARY_FLOAT or BINARY_DOUBLE datatype. It is a VARCHAR2 datatype.

select * from t1 where f3 is nan;
F1 F2 F3
---------- -------------------- ----------
4 654.213 Nan

select * from t1 where f3 is not nan;
F1 F2 F3
---------- -------------------- ----------
1 string one 1.235E+006
2 234.5678 Inf
5 string three -Inf

Note: NULL is neither a NAN, nor a not NAN. BINARY_FLOAT_INFINITY is special number, so not NAN is return TRUE for the BINARY_FLOAT_INFINITY value.

You can use the IS [NOT] INFINITY to test infinity condition.

SQL> select * from t1 where f3 is infinite;
F1 F2 F3
---------- -------------------- ----------
2 234.5678 Inf
5 string three -Inf

SQL> select * from t1 where f3 is not infinite;
F1 F2 F3
---------- -------------------- ----------
1 string one 1.235E+006
4 654.213 Nan

Note: NULL is neither a INFINITE number, nor a not INFINITE number.

SQL> select * from t1 where f3 is null;
F1 F2 F3
---------- -------------------- ----------
3 string two

SQL> select * from t1 where f3 is not null;
F1 F2 F3
---------- -------------------- ----------
1 string one 1.235E+006
2 234.5678 Inf
4 654.213 Nan
5 string three -Inf

BINARY_FLOAT_INFINITY and BINARY_FLOAT_NAN are special values. They are not NULL.

Binary floating-point numbers are stored using binary precision, so it can not represent all values
using decimal precision exactly.

SQL> select * from t1 where f3=1234567.89103245678;
F1 F2 F3
---------- -------------------- ----------
1 string one 1.235E+006

SQL> select * from t1 where f3=1234567.89103245;
F1 F2 F3
---------- -------------------- ----------
1 string one 1.235E+006

SQL> select * from t1 where f3=1234567.8;
no rows selected

SQL> select * from t1 where f3=1234567.9;
F1 F2 F3
---------- -------------------- ----------
1 string one 1.235E+006
SQL> select * from t1 where f3=1234567;
no rows selected

SQL> select * from t1 where f3=1234568;
no rows selected

Now, we add another column for BINARY_DOUBLE datatype, and update the value of BINARY_DOUBLE column with the same value of the BINARY_FLOAT datatype.

update t1 set f4=1234567.89103245678 where f1=1;
update t1 set f4=binary_double_infinity where f1=2;
update t1 set f4=null where f1=3;
update t1 set f4=binary_double_nan where f1=4;
update t1 set f4=-binary_double_infinity where f1=5;
SQL> commit;
Commit complete.

SQL> select * from t1;
F1 F2 F3 F4
---------- -------------------- ---------- ----------
1 string one 1.235E+006 1.235E+006
2 234.5678 Inf Inf
3 string two
4 654.213 Nan Nan
5 string three -Inf -Inf

Note: The BINARY_FLOAT_INFINITY is identical with the BINARY_DOUBLE_INFINITY. Also, the BINARY_FLOAT_NAN is identical with the BINARY_DOUBLE_NAN.

The interesting thing is that the value of BINARY_FLOAT and BINARY_DOUBLE for row 1 is not equal for row 1, even you insert it using the same literal value.

SQL> select * from t1 where f3=f4;
F1 F2 F3 F4
---------- -------------------- ---------- ----------
2 234.5678 Inf Inf
4 654.213 Nan Nan
5 string three -Inf -Inf

SQL> select * from t1 where f3<>f4;
F1 F2 F3 F4
---------- -------------------- ---------- ----------
1 string one 1.235E+006 1.235E+006

This is because Oracle stores different values for different datatype.

SQL> select dump(f3) dumpf3, dump(f4) dumpf4 from t1 where f1=1;
DUMPF3 DUMPF4
------------------------------ --------------------------------------------------
Typ=100 Len=4: 201,150,180,63 Typ=101 Len=8: 193,50,214,135,228,26,179,254

Also, you can insert BINARY_FLOAT_INFINITY value or BINARY_FLOAT_NAN value in a BINARY_DOUBLE datatype column, and insert BINARY_DOUBLE_INFINITY and BINARY_DOUBLE_NAN in a BINARY_FLOAT datatype column.

insert into t1 values (6, null, BINARY_FLOAT_INFINITY, BINARY_FLOAT_INFINITY);

insert into t1 values (7, null, BINARY_DOUBLE_INFINITY, BINARY_DOUBLE_INFINITY);

commit;

SQL> select f1, f3, f4, dump(f3) dumpf3, dump(f4) dumpf4 from t1;
F1 F3 F4 DUMPF3 DUMPF4

---------- ---------- ---------- ------------------------------ ------------------------------------

1 1.235E+006 1.235E+006 Typ=100 Len=4: 201,150,180,63 Typ=101 Len=8: 193,50,214,135,228,26,179,254

2 Inf Inf Typ=100 Len=4: 255,128,0,0 Typ=101 Len=8: 255,240,0,0,0,0,0,0

3 NULL NULL

4 Nan Nan Typ=100 Len=4: 255,192,0,0 Typ=101 Len=8: 255,248,0,0,0,0,0,0

5 -Inf -Inf Typ=100 Len=4: 0,127,255,255 Typ=101 Len=8: 0,15,255,255,255,255,255,255

6 Inf Inf Typ=100 Len=4: 255,128,0,0 Typ=101 Len=8: 255,240,0,0,0,0,0,0

7 Inf Inf Typ=100 Len=4: 255,128,0,0 Typ=101 Len=8: 255,240,0,0,0,0,0,0

No comments:

Post a Comment