Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 0.1 + 0.2 = 0.3  [new]
DFilushin
Member

Откуда: Новосибирск
Сообщений: 239
Доброе утро

немного пятничная тема.
Запрос
select 0.1 + 0.2 from dual

на oracle выдаёт корректный ответ 0.3

На Python, Java, Perl и других языках
.1 + .2
0.30000000000000004

Вопрос возникает, какая разница в механизмах расчётов в СУБД и ЯП?
Как писать код на яве в оракле с оглядкой на эту проблему.

Кстати, Firebird тоже корректно вычисляет
select 0.1 + 0.2 from rdb$database
10 авг 18, 05:40    [21637090]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Щукина Анна
Member

Откуда:
Сообщений: 1104
DFilushin,
вы бы ещё указали типы данных в случае с ораклом и с ЯПами.... Если в ваших ЯПах это что-то из серии флоат (float), то ничего удивительно. Флоат - это приблизительный тип. Соответственно, и результат в нем будет - тоже приблизительный.

10 авг 18, 05:57    [21637092]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
DFilushin
Member

Откуда: Новосибирск
Сообщений: 239
Щукина Анна,

для питона набирал в консоли, без указания типов, он же с динам. типизацией
10 авг 18, 06:05    [21637093]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Вячеслав Любомудров
Member

Откуда: Владивосток
Сообщений: 17845
tst> select .1+.2 from dual;

       .1+.2
------------
          .3

tst> select .1d+.2d from dual;

     .1D+.2D
------------
    3.0E-001

tst> set numwidth 40
tst> select .1d+.2d from dual;

                                 .1D+.2D
----------------------------------------
                 3.0000000000000004E-001
10 авг 18, 06:14    [21637094]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
DFilushin
Member

Откуда: Новосибирск
Сообщений: 239
Вячеслав Любомудров,

здесь вы указали тип принудительно
Какой механизм используется для простого "нетипизированного" вычисления?
10 авг 18, 06:41    [21637099]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Вячеслав Любомудров
Member

Откуда: Владивосток
Сообщений: 17845
А по умолчанию NUMBER со своей точностью 39-40 знаков
tst> set numwidth 42
tst> select .0987654321098765432109876543210987654321 from dual;

 .0987654321098765432109876543210987654321
------------------------------------------
 .0987654321098765432109876543210987654321

tst> select .09876543210987654321098765432109876543219 from dual;

.09876543210987654321098765432109876543219
------------------------------------------
 .0987654321098765432109876543210987654322
10 авг 18, 07:15    [21637105]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Elic
Member

Откуда: 1984. Выбраковка финно-угром продолжается. КЯЗ
Сообщений: 28295
Вячеслав Любомудров
А по умолчанию NUMBER
А в PL/SQL ещё и PLS_INTEGER.
10 авг 18, 07:22    [21637111]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16787
Щукина Анна
Флоат - это приблизительный тип. Соответственно, и результат в нем будет - тоже приблизительный.

Это типа шутка такая была?
10 авг 18, 12:48    [21637618]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
IMNO
Member

Откуда:
Сообщений: 65
andrey_anonymous
Щукина Анна
Флоат - это приблизительный тип. Соответственно, и результат в нем будет - тоже приблизительный.

Это типа шутка такая была?

Почему шутка? Флоат же аппаратный тип, а не программный. Из-за грубого округления в двоичной системе счисления и возникает неточность.
10 авг 18, 12:57    [21637638]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Зашедший
Member

Откуда: Москва
Сообщений: 3934
DFilushin
Вопрос возникает, какая разница в механизмах расчётов в СУБД и ЯП?
Как писать код на яве в оракле с оглядкой на эту проблему.
У меня возникает другой вопрос - как работающий в IT человек может не знать отличий binary и decimal форматов? Про стандарт IEEE 754 не буду вспоминать уж.
10 авг 18, 13:02    [21637654]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16787
IMNO
Флоат же аппаратный тип, а не программный. Из-за грубого округления в двоичной системе счисления и возникает неточность.

Рукалицо.
Не поверите - в современной вычислительной технике ВСЕ данные - двоичные, "программные" тоже.
Впрочем, про IEEE 754 тут уже напомнили - несведущим рекомендовал бы ознакомиться хотя бы поверхностно.
10 авг 18, 13:16    [21637701]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
andreymx
Member

Откуда: Запорожье
Сообщений: 48494
в делфи тип currency подходит для денег
10 авг 18, 14:42    [21637963]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16787
andreymx
в делфи тип currency подходит для денег

Для денег подойдет любая реализация fixed point, самая распространенная - представление в виде целого, помноженного на 10 в интересующей степени.
Из плавающих - подойдет реализация с десятичным порядком, к примеру - см. decimalXX из IEEE 754—2008, он же ISO/IEC/IEEE 60559:2011.
10 авг 18, 14:55    [21638006]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Hett
Member

Откуда: Бийск, Новосибирск
Сообщений: 13257
andrey_anonymous,

С каких пор decimal с плавающей точкой?
12 авг 18, 09:03    [21639022]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
-2-
Member

Откуда:
Сообщений: 13862
Hett
С каких пор decimal с плавающей точкой?
Decimal из sql и инженерный не одно и то же. А точке все равно, в чем плавать.
12 авг 18, 11:31    [21639083]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Зашедший
Member

Откуда: Москва
Сообщений: 3934
Hett
andrey_anonymous,
С каких пор decimal с плавающей точкой?
Это уже становится не смешно. Позор какой-то, люди типа "работают" в IT и при этом не желают знать базовых стандартов данных
IEEE 754 указывает следующие типы форматов с плавающей запятой:
Стандарт
-binary16
-binary32
-binary64
-binary128
-binary256
-decimal32
-decimal64
-decimal128

12 авг 18, 12:27    [21639121]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Excession
Member

Откуда:
Сообщений: 25
DFilushin
Доброе утро
на oracle выдаёт корректный ответ 0.3

Давай поделим 1 на 3 в троичной системе отсчета, что получится?
Получится в естественной форме записи числа 0.1 в троичной системе отсчета.

Теперь поделим 1 на 3 в десятичной системе отсчета и о ужас получится 0.3333333333 ну и так далее в периоде,
вах вах вах в одной системе отсчета так красиво 0.1, а в другой 0.(3) как же так? :)
12 авг 18, 13:52    [21639161]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
IMNO
Member

Откуда:
Сообщений: 65
До этой темы я докумал, что понимаю как хранятся числа.
Перечитал IEEE754. Ещё раз перечитал. Погуглил статьи про фиксированную/плавающую запятую.
Перечитал стандарт ещё несколько раз.
Теперь я вообще ничего не понимаю.

Вячеслав Любомудров приводил пример.

select .1d+.2d from dual;


Здесь результат принудительно приводится к типу decimalXX, который из IEEE754.

Откуда берётся "четвёрка":
Переведём 0.1 в двоичную систему счисления:

0.1 * 2 = 0.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2


Дальше можно не продолжать.
Результат: 0.1 = 0.000110011
Можно заметить что 0011 в периоде.
То есть как и ожидалось, 0.1 в двоичную систему нормально не переводится.
Нужно выбрать точность перевода. Отсюда и "четверка" в примере выше.

Но почему "правильный результат" получился в этом примере?

select .1+.2 from dual;


Почему результат без "непредвиденной" дроби? Что за магия?

Зашедший писал:
Зашедший
не знать отличий binary и decimal


То есть могу предположить, что во втором примере(второй пример в моем сообщении) тип binaryXX.
Тогда я вообще ничего не понимаю. Ведь binaryXX почти тоже самое что и decimalXX.
У них только основание различается, то есть тоже должна быть погрешность.

Короче, что происходит?
13 авг 18, 17:17    [21640873]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Зашедший
Member

Откуда: Москва
Сообщений: 3934
IMNO
Ведь binaryXX почти тоже самое что и decimalXX.
У них только основание различается, то есть тоже должна быть погрешность.
Децимал - даже близко не то же самое. 0.1 с десятичным основанием переведется как 1х10^-1
13 авг 18, 18:28    [21640988]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Excession
Member

Откуда:
Сообщений: 25
IMNO
Почему результат без "непредвиденной" дроби? Что за магия?

Магия типа Number в Oracle
13 авг 18, 23:35    [21641211]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Вячеслав Любомудров
Member

Откуда: Владивосток
Сообщений: 17845
IMNO
select .1d+.2d from dual;


Здесь результат принудительно приводится к типу decimalXX, который из IEEE754.
Все-таки открывай учебник по продукту с которым работаешь/разбираешься
D - это не от Decimal, а от Double
+ Есть еще F
tst> select .1f+.2f from dual;

                                   .1F+.2F
------------------------------------------
                           3.00000012E-001

IMNO
Переведём 0.1 в двоичную систему счисления:

Результат: 0.1 = 0.000110011
Можно заметить что 0011 в периоде.
Ну, в общем, чем больше этих периодов, том точнее приближение, как оно укладывается в 64 Double-precision floating-point format можно посмотреть, например, тут
IMNO
Но почему "правильный результат" получился в этом примере?

select .1+.2 from dual;


Почему результат без "непредвиденной" дроби? Что за магия?
Потому что тип NUMBER хранится не по основанию 2, а по основанию 100
14 авг 18, 04:24    [21641249]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
IMNO
Member

Откуда:
Сообщений: 65
Вячеслав Любомудров
как оно укладывается в 64 Double-precision floating-point format можно посмотреть, например, тут


Крутая ссылка, спасибо.

Вячеслав Любомудров

IMNO
Но почему "правильный результат" получился в этом примере?

select .1+.2 from dual;


Почему результат без "непредвиденной" дроби? Что за магия?
Потому что тип NUMBER хранится не по основанию 2, а по основанию 100


Так.
Получается, что в Oracle:
1. BINARY_FLOAT и BINARY_DOUBLE - это binaryXX из IEEE754
2. NUMBER - это decimalXX из IEEE754

Все три типа "программные", а не "аппаратные".

Немного отступления. Что я имею ввиду, когда пишу "стандарт".
Этакий чёрный ящик, у которого есть входы и выходы. Совершенно не важно, как данные хранятся внутри(программно, аппаратно или ещё как-нибудь), главное чтобы на выходе результат был такой, какой описан в стандарте.

То есть binaryXX говорит, что может должна быть неточность после N-ого знака.
DecimalXX говорит, что до N-ой позиции неточности быть не должно.
То есть как писал andrey_anonymous, тот же decimalXX всё равно хранится как двоичный код, но результат должен выдаваться точный.
То есть при использовании типа decimalXX отрабатывает алгоритм который сглаживает неточность хранения чисел в двоичном коде.

Поправьте пожалуйста, если что не так.
16 авг 18, 11:33    [21644173]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
Вячеслав Любомудров
Member

Откуда: Владивосток
Сообщений: 17845
Оракловый NUMBER не имеет никакого отношения к IEEE754 и ссылочку на его потроха тебе приведена
Больше всего оно похоже на BCD (https://ru.wikipedia.org/wiki/Двоично-десятичный_код), бывший популярен во многих финансово-ориентированных языках (Cobol, PL/1), только основание не 10, а 100
16 авг 18, 11:39    [21644180]     Ответить | Цитировать Сообщить модератору
 Re: 0.1 + 0.2 = 0.3  [new]
andrey_anonymous
Member

Откуда: Москва
Сообщений: 16787
IMNO
Поправьте пожалуйста, если что не так.

Поправляю.
Числа с плавающей точкой хранятся как пара целых чисел. Целых, обратите внимание.
Все истории про неточности - это истории про множества представимых чисел и выбор ближайшего представимого для непредставимого (правила округления).
А вся разница между binary, decimal и тем же oracle number - это основание логарифма. Десятичный или двойка. Все остальное - в контексте обсуждаемой проблемы от лукавого.
"стреляет" основание логарифма при нормализации. Не будь ее - не стреляло бы, но имели бы место другие спецэффекты.
И еще. Разделение на "программные" и "аппаратные" в том пещерном понимании, которое тут демонстрировалось - суть фейк.
16 авг 18, 13:14    [21644387]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить