Общая рекомендация

Аргументы всех математических функций могут задаваться в виде < SQL-параметра >, который должен содержать спецификацию типа данных параметра, например,

select abs(? (double));
-67.41
|                 67.41|

select mod(? (double), ? (int));
236.78
23
|      6.78000000000003|

СУБД ЛИНТЕР поддерживает два типа приближенных вещественных данных: REAL и DOUBLE (DOUBLE PRECISION), различающихся между собой точностью представления данных (тип данных REAL имеет меньшую точность по сравнению с DOUBLE). При математических вычислениях с использованием одновременно разных вещественных типов данных точность промежуточных (или окончательных) результатов может снижаться. Поэтому рекомендуется при использовании функций от аргументов типа DOUBLE PRECISION хранить значения аргументов этих функций также в столбцах типа DOUBLE PRECISION, а не REAL.

Пример

Сравнение точности результатов при использовании вещественных типов данных разной точности.

create or replace table t_double (d double precision);
create or replace table t_real(r real);
insert into t_real values (1e+20);
insert into t_real values (999.4);
insert into t_double select * from t_real;

select * from t_double;
 D
 -
| 1.00000002004088e+020|
|      999.400024414063|
create or replace table t1_double (d1 double precision);
create or replace table t2_double (d2 double precision);
insert into t2_double values (1e+20);
insert into t2_double values (999.4);
insert into t1_double select * from t2_double;

select * from t1_double;
 D1
 -
|                1e+020|
|                 999.4|
create or replace table tst (r real);
insert into tst values (12.35635);
insert into tst values (98.61324);
insert into tst values (1e+20);

select ceil(r), floor(r) from tst;
|                    13|                    12|
|                    99|                    98|
| 1.00000002004088e+020| 1.00000002004088e+020|

Из примера видно, что результат округления с недостатком оказался больше исходного значения. Для правильного результата нужно использовать тип данных DOUBLE:

create or replace table tst (d double);
insert into tst values (12.35635);
insert into tst values (98.61324);
insert into tst values (1e+20);
select ceil(d), floor(d) from tst;
|                    13|                    12|
|                    99|                    98|
|                1e+020|                1e+020|

Примечание

Для сравнения вещественных чисел с заданной точностью рекомендуется использовать следующую конструкцию:

select abs(a-b)/greatest(abs(a),abs(b)), abs(a-b) < = DBL_EPSILON * greatest(abs(a),abs(b)) from test_tbl;

где DBL_EPSILON (или FLT_EPSILON для FLOAT) – заданная точность сравнения.

Пример:

create or replace table test_tbl(a float, b float);
insert into test_tbl values(0.000585955393034, 0.000585955393035);
insert into test_tbl values(0.00058595539303496, 0.00058595539303497);
insert into test_tbl values(0.000585955393034964, 0.000585955393034965);
insert into test_tbl values(0.000585955393034965444, 0.0005859553930349654446);

select abs(a-b)/greatest(abs(a),abs(b)) relative_difference, abs(a-b) < = 1e-12 * greatest(abs(a),abs(b)) comparison_result from test_tbl;
|relative_difference  |comparison_result|
|1.70673074399179e-12 |F                |
|1.68378683546467e-14 |T                |
|1.66528368342661e-15 |T                |
|0                    |T                |

select abs(a-b)/greatest(abs(a),abs(b)) relative_difference, abs(a-b) < = 1e-14 * greatest(abs(a),abs(b)) comparison_result from test_tbl;
|relative_difference  |comparison_result|
|1.70673074399179e-12 |F                |
|1.68378683546467e-14 |F                |
|1.66528368342661e-15 |T                |
|0                    |T                |

select abs(a-b)/greatest(abs(a),abs(b)) relative_difference, abs(a-b) < = 1e-16 * greatest(abs(a),abs(b)) comparison_result from test_tbl;
|relative_difference  |comparison_result|
|1.70673074399179e-12 |F                |
|1.68378683546467e-14 |F                |
|1.66528368342661e-15 |F                |
|0                    |T                |