SQLite показывает число с плавающей запятой, когда сумма вычитается из той же общей суммы в литерале - PullRequest
0 голосов
/ 14 марта 2020

У меня есть таблица с столбцом amount. Когда сложите, сумма выглядит нормально. Но когда он вычитается из того же итогового значения в литерале, появляется плавающая точка.

Рассмотрим этот пример:

create table a(
    id number,
    amount number(9,2),
    constraint a_pk primary key (id)
);

insert into a values(1006118,1083.33);
insert into a values(1006123,614.29);
insert into a values(1006124,783.33);
insert into a values(1006096,783.33);
insert into a values(1006104,833.33);
insert into a values(1006115,533.33);
insert into a values(1006116,633.33);
insert into a values(1006092,683.33);

Сумма суммы составляет 5947,6. Разница 5947.6-sum(amount) должна быть равна нулю, но SQLite возвращает 9.09494701772928e-13.

select sum(amount), 5947.6-sum(amount) difference
from a;

Как будто отсутствует значение. Или я что-то упустил?

Ответы [ 2 ]

2 голосов
/ 14 марта 2020

Цифровая компьютерная арифметика с плавающей точкой c неточна. Некоторые десятичные числа не могут быть представлены точно как числа с плавающей запятой, поэтому, когда вы запрашиваете сумму некоторых неточно представимых чисел, результат не представляется внутри как точное десятичное число, и поэтому, когда вы вычитаете то, что вы считаете точным десятичным результатом вы не получите ноль.

Обычно такую ​​неточность можно скрыть с осторожным округлением:

select round(sum(amount),2), 5947.6-round(sum(amount),2) difference from a;

См. Что должен знать каждый учёный-компьютерщик об арифметике с плавающей точкой c

1 голос
/ 14 марта 2020

Читы SQLite для типов данных . В отличие от других баз данных, он игнорирует ваш объявленный тип столбца и угадывает тип на основе того, что вы вставляете. number не является допустимым типом SQL, но SQLite это не волнует.

Числа с плавающей запятой являются лишь приблизительными и будут накапливать ошибки, если вы выполните для них вычисления. Это общая проблема с числами с плавающей запятой. SQLite превратит 1083.33 в число с плавающей запятой.

Вам понадобится число произвольной точности c тип данных , например decimal или numeric. К сожалению, в SQLite их нет.

Вы можете уменьшить проблему путем округления.

select
  sum(amount),
  round(5947.6-sum(amount), 2) difference
from a;

Но это не на 100% точно, так как ошибки все равно будут накапливаться, вы просто их устраните. в конце. Если вам нужна точность, сохраняйте все в целых числах и сдвигайте их значения на два десятичных знака.

sqlite> insert into a values(1006118,108333);
sqlite> insert into a values(1006123,61429);
sqlite> insert into a values(1006124,78333);
sqlite> insert into a values(1006096,78333);
sqlite> insert into a values(1006104,83333);
sqlite> insert into a values(1006115,53333);
sqlite> insert into a values(1006116,63333);
sqlite> insert into a values(1006092,68333);
sqlite> select sum(amount), 594760-sum(amount) difference from a;
sum(amount)  difference
-----------  ----------
594760       0         
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...