Skip to end of metadata
Go to start of metadata

double, float data type 사용 시 주의사항


알티베이스의 double data type 은 C언어의 double 형 데이터타입과 동일합니다.   double data type은 고정 소수점 방식보다 넓은 범위의 수를 나타낼 수 있는 반면, 근사값으로 표현되기 때문에 

그 값이 정확하지 않을 수 있으며 소숫점 뒤의 의미없는 값들이 지나치게 길게 나올수 있습니다.

또한 double/float 형 값을  iSQL로  조회하거나  iloader 로 export 할 경우  소수점 이하의 값이 잘려서 나오지 않을 수 있습니다.  

따라서 소수점이하의 값을  정확하게  조회하거나 저장하기 위해서는    numeric 과 같은 고정 소수점  숫자타입을 사용하여야 합니다.

영향을 받는 버전


모든 알티베이스 버전에 동일하게 해당하는 사항입니다.

 

 

double형 숫자값이 잘려서 표현되는 예 


iSQL 에서 값이 잘려서 표현되는 현상

iSQL> create table t1 ( c1 double );
Create success.

iSQL> desc t1;
[ TABLESPACE : SYS_TBS_MEM_DATA ]
[ ATTRIBUTE ]                                                        
------------------------------------------------------------------------------
NAME                                     TYPE                        IS NULL
------------------------------------------------------------------------------
C1                                       DOUBLE          FIXED      

iSQL>  insert into t1 values ( double'100.00000000000001421085471520200372');                                    <-- double형 칼럼에 double형의 긴 소수점 이하값을 갖는  숫자를 입력한다.
1 row inserted.

iSQL> select c1, to_char(c1) from t1;
C1                     TO_CHAR(C1)                                                      
--------------------------------------------------------------------------------------------
100                    100                                                                                                                                      <--- 소수점이하의 값이 잘려서 조회

iSQL>


iSQL> select * from t1 where c1 = 100.00000000000001421085471520200372;                                      <-- 조회 조건값이 잘려서  조회되지 않을 수 있다.
C1                    
-------------------------
No rows selected.

iSQL> select c1, to_char(c1) from t1 where c1 = double'100.00000000000001421085471520200372' <-- 조회 조건값을  형변환시키면 원하는 값을 찾을 수 있다.
C1                     TO_CHAR(C1)                                                      
--------------------------------------------------------------------------------------------
100                    100                                                                                                                                   <---  그러나 조회되서 출력되는 값을 잘려서 표현된다.
1 row selected.

 

 iLoader 에서 data 를 export 했을 때

$ iloader -s localhost -u SYS -p MANAGER out -f SYS_T1.fmt -d SYS_T1.dat -log SYS_T1.log
$ cat SYS_T1.dat
100                     <--- 소수점이하가  잘린 값이  export된다.

 

프로그램에서 double 형 호스트 변수에 가져올 올 경우는 정상 조회된다.

/* select.c */
...................
...................
    EXEC SQL BEGIN DECLARE SECTION;
    double c1;         // select 출력용 double 호스트변수
    double ins_c1;     // insert 용 double 호스트변수
    EXEC SQL END DECLARE SECTION;

    ins_c1 = 100.00000000000001421085471520200372;

    EXEC SQL INSERT INTO T1 values ( :ins_c1 );
    if (sqlca.sqlcode != SQL_SUCCESS)
    {
        printf("Error : [%d] %s\n\n", SQLCODE, sqlca.sqlerrm.sqlerrmc);

    }

    EXEC SQL SELECT C1 INTO :c1 FROM T1 limit1;
    /* check sqlca.sqlcode */
    if (sqlca.sqlcode == SQL_SUCCESS)
    {
        printf("c1 = %.32f \n", c1);
    }
.................
.................
shell> ./select   ( 프로그램 실행)
<SELECT>
c1 = 100.00000000000001421085471520200372   <-- 정상적인 값이 출력된다.

 

Oracle sqlplus 에서도 동일한 현상

 확인결과 Oracle 의 sqlplus 에서도 동일하게 값이 잘리는 현상이 있습니다.

SCOTT@orcl> create table t1 ( c1 binary_double );

Table created.

SCOTT@orcl> insert into t1 values ( 100.00000000000001421085471520200372 );

1 row created.

SCOTT@orcl> select c1, to_char(c1) from t1;

        C1 TO_CHAR(C1)
---------- ----------------------------------------
  1.0E+002 1.0000000000000001E+002

문제 해결방안


소수점이하의 값을  정확하게  조회하거나 저장하기 위해서는    numeric(scale, presicion )   과 같은 고정 소수점  숫자타입을 사용하여야 합니다.

아래는   numeric 형을 사용할 경우 iSQL에서  값이 정상 조회되는 실행 예입니다.

iSQL>  create table t2 ( c1 numeric(35, 32 ) );
Create success.
iSQL> desc t2;
[ TABLESPACE : SYS_TBS_MEM_DATA ]
[ ATTRIBUTE ]                                                        
------------------------------------------------------------------------------
NAME                                     TYPE                        IS NULL
------------------------------------------------------------------------------
C1                                       NUMERIC(35, 32) FIXED      

 

iSQL> insert into t2 values ( 100.00000000000001421085471520200372 );
iSQL> insert into t2 values ( 123.00000000000001421085471520200372 );
iSQL> insert into t2 values ( 100.12345 );


iSQL> select c1, to_char(c1) from t2;     <-- iSQL 상에서 소수점 이하 값을 그대로 표현하기 위해서 to_char 함수를 사용하여 char 형으로 형변환합니다.
C1          TO_CHAR(C1)                                                      
---------------------------------------------------------------------------------
100         100.00000000000001421085471520200372                             
123         123.00000000000001421085471520200372                             
100.12345   100.12345    

 

iSQL> select c1, to_char(c1) from t2 where c1 = 100.00000000000001421085471520200372;      <--  조건값으로 조회할 경우 별도의 형변환이 필요없이 사용 가능합니다.
C1          TO_CHAR(C1)                                                      
---------------------------------------------------------------------------------
100         100.00000000000001421085471520200372                             
1 row selected.

 

 

  • No labels