Здравствуйте, netch80, Вы писали:
N>Это не ко мне вопрос. Ряд стандартов так требуют для промежуточных значений в расчётах (на самом деле речь шла про США и центы).
Вот именно промежуточных, по нашим правилам. За США не скажу.
N>Я говорю именно о задаче. В матфизике нет необходимости разделять число на части с точным совпадением суммы этих частей до последней значащей цифры. В финансах это обязательное условие при любой подобной операции — "итого", остатки и балансы должны сходиться точно, где вообще компьютер может этому помочь.
+1
Здравствуйте, FrozenHeart, Вы писали:
FH>Вот есть, например, всё же то число 0.1, для которого binary float выбирает ближайшее представимое значение (какое-нибудь 0.10000000000000001). Если мы сложим такое число три раза, то явно получим не чистое 0.3, а что-то вроде 0,30000000000000003
Прикинуть можно, зная количество значащих цифр в том же double.
Свою оценку уже приводил — сложение многих тысяч миллиардных сумм представленных с точностью до копейки, но это близко к той границе, где точности double может не хватить в принципе для представления точных сумм, а не только потому, что они в двоичном виде представляются не точно.
И на финансовые расчеты это не похоже.
Здравствуйте, FrozenHeart, Вы писали:
N>>>>и они хуже потому, что с ростом base увеличиваются ошибки округления и дребезг значения младшего разряда. FH>>>С ростом base от 2 до 10? FH>Не совсем понимаю, почему ошибки округления увеличиваются. Можно пример или какое-нибудь пояснение, пожалуйста?
Представим себе случаи с очень близкой точностью — например, 6 десятичных разрядов (точность до 1/1000000 у самоого большого значения мантиссы) или 20 двоичных (до 1/1048576 соответственно).
Число от 524288 до 999999 представляется в обоих случаях с точностью до 1.
От 1000000 до 1048576 — в двоичном до 1, в десятичном до 10.
Вниз:
От 262144 до 524288 — в двоичном до 1/2 (различаются, например, последовательно 345678, 345678.5 и 345679), но в десятичном — до 1.
От 131072 до 262144 — в двоичном до 1/4, в десятичном до 1.
От 100000 до 131072 — в двоичном до 1/8, в десятичном до 1.
От 65536 до 100000 — в двоичном до 1/8, в десятичном до 1/10 (да, небольшой период наоборот).
От 32768 до 65536 — в двоичном до 1/16, в десятичном до 1/10.
И так далее.
В случае base16 (S/360) случаев, когда десятичная точнее, вообще нет.
Второй фактор — резкое возрастание неточности округления младшего разряда, сама по себе ситуация, когда два очень близких значения округляются до границы, которая для них разная не в 2, а в 10 или 16 раз. Тут закономерности сложнее, без формул не обойтись. Некоторое обсуждение есть в FMM.
Здравствуйте, FrozenHeart, Вы писали:
N>>"Чисто гипотетически" сумма огромного набора чисел это не совсем типично для финансовых расчётов. N>>Если речь именно про суммирование, в значительном числе случаев помогает Kahan summation. Аналогичное можно придумать для умножения и деления, хотя и дорого N>>Но именно из-за таких опасений и переходят или на decimal float с контролем inexact condition, как я описывал раньше, или на fixed point. FH>Так, всё потихоньку встаёт на свои места, спасибо
FH>Т.е. binary floats: FH>- Не могут точно представить некоторое множество дробных чисел и, как результат, могут накапливать ещё большую ошибку в результате выполнения над ними различных арифметических операций
Это одинаково для всех. Отличаются они тут явно именно для конечных десятичных дробей.
FH>Decimal floats: FH>- В отличие от binary floats, могут точно представить любую десятичную дробь
_Конечную_ и ограниченной длины. А то число π — это тоже десятичная дробь
FH>- Не могут представить определённое множество значений, получающихся в процессе выполнения арифметических операций (например, 1/3)
Одинаково для обоих.
FH>- Могут сигнализировать о выходе за пределы precision'а (inexact condition) при помощи специального флага или исключения
Одинаково для обоих.
FH>Fixed point numbers: FH>- Могут точно представить любое значение в пределах заданного precision'а, однако, очевидно, выполняют округление до заданного кол-ва знаков после запятой FH>Всё сказал правильно или всё же упустил что-то важное?
N>Это одинаково для всех. Отличаются они тут явно именно для конечных десятичных дробей.
В общем, decimal floats не могут представить лишь неконечные дроби наподобие числа Pi?
N>_Конечную_ и ограниченной длины. А то число π — это тоже десятичная дробь
А в чём разница между конечной дробью и дробью с ограниченной длиной?
Здравствуйте, FrozenHeart, Вы писали: FH>- Продолжать использовать double'ы, не забывая о корректном сравнении и прочих подводных камнях
double вполне достаточно в большинстве случаев. а есть кстати, еще long double, стоит попробовать сравнить результаты с обеими типами
FH>- Начать использовать decimal floating point numbers и получить преимущество (?). Сравнивать их через operator== без epsilon можно, кстати?
это для бухгалтерии, так как даже с long double часто бывают числа в десятичной записи выглядящие как 1 + 2 = 2.99999999999999999999999999999999999
приходится применять округление даже там, где его никто не ждет. а у бухгалтерии еще и округление свое (ога) и это рождает большую путаницу. поэтому где деньги, там decimal, и где decimal — там деньги
FH>- Начать использовать fixed point numbers и получить преимущество (?)
это используется в геймдеве для девайсов без floating point. очень неудобный и стремный тип
FH>- Переводить double'ы в int'ы, выполнять над ними все необходимые операции и конвертировать обратно в double для передачи фреймворку?
это еще зачем?
Здравствуйте, FrozenHeart, Вы писали:
N>>_Конечную_ и ограниченной длины. А то число π — это тоже десятичная дробь FH>А в чём разница между конечной дробью и дробью с ограниченной длиной?
Имелось в виду — чтобы влезала в размер мантиссы данного типа.
Для IEEE'шных decfloat32 это 7 цифр, decfloat64 — 16.
__>double вполне достаточно в большинстве случаев. а есть кстати, еще long double, стоит попробовать сравнить результаты с обеими типами
long double в случае Visual C++ то же самое, что и double, а в стандарте C++ и вовсе сказано следующее:
There are three floating point types: float, double, and long double. The type double provides at least as much precision as float, and the type long double provides at least as much precision as double
__>это используется в геймдеве для девайсов без floating point. очень неудобный и стремный тип
А что неудобного и стрёмного?
__>это еще зачем?
Сложение, вычитание и умножение без погрешностей?
Если у вас вычислений относительно много (например в цикле идут умножения/деления/сложения/вычитания), то с рациональными числами их компоненты очень быстро станут гигантскими, а арифметика с длинными числами это тоже не подарок. Ну и куча операций типа корня и тд над рациональными числами тоже дадут неточный результат. Так что это не панацея. Лучше разберитесь с ошибками округлениями и возьмите их под контроль.
Здравствуйте, FrozenHeart, Вы писали:
N>>Имелось в виду — чтобы влезала в размер мантиссы данного типа. N>>Для IEEE'шных decfloat32 это 7 цифр, decfloat64 — 16. FH>Понял, спасибо.
FH>На второй вопрос можете ответить, пожалуйста?
>>В общем, decimal floats не могут представить лишь неконечные дроби наподобие числа Pi?
А что непонятно? Я считаю предыдущее ответом на оба вопроса. Вообще, должно быть очевидно, что если само понятие "конечная дробь" введено в контексте десятичной арифметики, то и десятичный флоат будет конечным, а если нет — то надо перемерять и уточнять
Здравствуйте, FrozenHeart, Вы писали: __>>double вполне достаточно в большинстве случаев. а есть кстати, еще long double, стоит попробовать сравнить результаты с обеими типами FH>long double в случае Visual C++ то же самое, что и double, а в стандарте C++ и вовсе сказано следующее:
в gcc есть (?) __float128 и в случае отсутсвия поддержки всегда можно сэмулировать, возможно, достаточно эффективно. по крайней мере точно эффективнее decimal
__>>это используется в геймдеве для девайсов без floating point. очень неудобный и стремный тип FH>А что неудобного и стрёмного?
обычно одновременно совмещает в себе низкую точность и быстрое переполнение
FH>Сложение, вычитание и умножение без погрешностей?
если у нас дробной части нет и значения маленькие, то да. а такое часто бывает?
Здравствуйте, FrozenHeart, Вы писали:
FH> Вот такие ситуации в случае decimal floating point numbers разве могут когда-то зафейлиться?
Такие вещи нужно обсуждать с бизнес-аналистом или domain expert.
Все правила округления при вычислениях и порядок вычислений диктуется только бизнесом.
И никакое представление чисел тебе не поможет.
В финансах люди обычно используют десятичные числа, поэтому и в компьютере вычисления должны быть десятичными, с учётом требуемых способов округления.
Например, такой сценарий. Налоговая декларация, 3 партнёра ведут бизнес и получили прибыль $1000. По уставу компании участие в бизнесе описывается как равная доля.
Соответственно каждый получил $1000/3, что никак не делится. Поэтому в налоговой декларации предусмотрен флажок, который должен быть поставлен одному из партнёров — кому идут остатки: $333+$334+$333.
Или стандартная грабля. Продаёшь свой товар за $99.99, и должен платить НДС 20%.
Если ты продал 1000 единиц товара, то сколько ты должен заплатить НДС?
налог с продажи тысячи единиц товара:
(1000 * $99.99) * 20% = $9999 * 20% = $19998
или
сумма тысяч налогов с продажи каждого товара:
1000 * ($99.99 * 20%) = 1000 * $19.99 = $19990
какой ответ правильный? А оба могут быть правильные — зависит от требований бизнеса. И, кстати, вариантов — больше двух, я указал лишь два простейших.
Здравствуйте, ·, Вы писали:
·>Такие вещи нужно обсуждать с бизнес-аналистом или domain expert.
А если ТС сам себе бизнес-аналитик и этот самый "domain expert". Не все же на конвейере стоят.
·>Все правила округления при вычислениях и порядок вычислений диктуется только бизнесом. ·>И никакое представление чисел тебе не поможет.
ТС интересуется не внесет ли представление чисел дополнительных проблем никак не связанных с бизнес-логикой.
·>В финансах люди обычно используют десятичные числа, поэтому и в компьютере вычисления должны быть десятичными, с учётом требуемых способов округления.
У ТС свои особенности, в его продукте задействован (и похоже не на последних ролях) некий "фреймворк" работающий с double.
И инженеры и ученые тоже используют десятичные числа, но это не значит, что при научных и инженерных расчетах компьютере вычисления должны быть десятичными.
·>Например, такой сценарий. Налоговая декларация, 3 партнёра ведут бизнес и получили прибыль $1000. По уставу компании участие в бизнесе описывается как равная доля. ·>Соответственно каждый получил $1000/3, что никак не делится. Поэтому в налоговой декларации предусмотрен флажок, который должен быть поставлен одному из партнёров — кому идут остатки: $333+$334+$333.
Да, "последняя копейка" должна распределятся, если сумма задана.
·>какой ответ правильный? А оба могут быть правильные — зависит от требований бизнеса.
Первый, если мы в России.
·>И, кстати, вариантов — больше двух, я указал лишь два простейших.
+1
... << RSDN@Home 1.2.0 alpha 5 rev. 1495>>
Re: предлагаю ознакомиться со статьей на соседней ветке
__>в gcc есть (?) __float128 и в случае отсутсвия поддержки всегда можно сэмулировать, возможно, достаточно эффективно. по крайней мере точно эффективнее decimal
Ясно, спасибо за информацию.
__>обычно одновременно совмещает в себе низкую точность и быстрое переполнение
Точность же точно такая, какую указал разработчик, так что разве это может быть минусом?
Быстро переполнение чего?
__>если у нас дробной части нет и значения маленькие, то да. а такое часто бывает?
Тут согласен -- фигня.
Здравствуйте, pagid, Вы писали:
P>Статья несколько "в сторону". В сторону ПЛ/1.
дело вовсе не в PL/1 (на самом деле не в Коболе?)
Дело в том, что эти вопросы давно решены, в том числе и на аппаратном уровне — двоично-десятичная арифметика.
И вставлены в процессоры. А теперь начинают велосипед изобретать. Кобол уже решил вопросы финансовых расчетов, почему его решения не взять в другие языки?
Здравствуйте, FrozenHeart, Вы писали:
FH>·>Такие вещи нужно обсуждать с бизнес-аналистом или domain expert. FH>К сожалению (?), у нас нет таких людей.
Тогда ты сам должен знать или договориться с клиентами о том, что будет правильным резульатом. Твой вопрос аналогичен "какую мне операцию использовать — сложение или умножение, какая считает точнее"? Тот факт эти операции иногда дают одинаковый ответ не означает что они заменяемы. Ты должен знать что именно ты считаешь и использовать соответствующую арифметику.
Все эти представления чисел не позволяют делать произвольные вычисления с абсолютной точностью.
Я наблюдал, например, что налоговка использует округления в пользу налогоплательщика — налогооблагаемая прибыль округляется вниз, а налоговые вычеты — вверх.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай