N>В общем случае — да, остаться на привычных binary floats. N>Причина очень проста: base=10 ничего положительного тебе не даст (у тебя уже на входе и выходе binary)
Ну да, на входе и на выходе у меня binary floats, но ведь decimal floats дадут мне возможность не беспокоиться о неточном представлении чисел наподобие 0.1 и спокойно складывать их, ожидая, что 0.1 + 0.1 + 0.1 на самом деле будет равно 0.3
Или Вы о том, что decimal я в итоге сконструирую на основе binary float, который уже содержит эту ошибку, в связи с чем перевод из binary в decimal уже мог дать "ошибочное" значение?
N>и они хуже потому, что с ростом base увеличиваются ошибки округления и дребезг значения младшего разряда.
С ростом base от 2 до 10?
N>Они могут быть отражены как 1/3 Но в общем да, вопрос не в этом. Вопрос в следующем. Представь себе, что у тебя десятичная плавучка с 6 цифрами мантиccы. Если ты вычисляешь 9999.99+0.01, получаешь 10000.0, и этот результат точный. Если 9999.99+0.02, получаешь 10000.0, и это уже результат неточный (7-я цифра не влезла). IEEE754 предоставляет возможность узнавать про такие неточные результаты через inexact condition (флаг или исключение), и если ты считаешь в десятичной, эта ошибка будет генерироваться только если действительно происходит потеря точности в результате выхода нужных тебе цифр за пределы представляемого (как в этом примере потеряли один цент), а если в двоичном, она будет происходить практически при любых вычислениях с дробными частями, и ты не опознаешь реальный факт такой потери точности на фоне такого шума. N>Вот это то единственное, ради чего decimal float вообще могут быть нужны (а если инфраструктура такого не предоставляет, то она в целом бессмысленна, и лучше работать в более распространённых двоичных числах, или в fixed).
Правильно ли я Вас понял, что Вы пытаетесь донести до меня мысль о том, что decimal floats точно так же подвержены накапливаемым ошибкам, как и binary floats? Только если в случае binary floats такое сплошь и рядом (из-за того, что "неточно" представляемых чисел в нём гораздо больше -- всякие 0.1 и т.д.), то в случае decimal floats такое будет происходить хотя бы из-за превышения точности. Верно?
Извините, что переспрашиваю, тема для меня кажется сложной, и я хочу убедиться, что правильно понимаю, о чём, собственно, идёт речь.
P>С фреймворков же обмениваешься в double, никакого смысла переводить из одного в другое и обратно нет. А так да, если бы программа не завесила от фреймворка, вариант с fixed point numbers возможно и был бы разумным. Но в любом же случае от проблем с округлением он не спасает. И в финансовых расчетах ситуации наподобие 1/3 сплошь и рядом, и результат все равно будет зависить от того сколько знаков после точки зафиксировать в "fixed point numbers" и когда округлять.
А есть ли у decimal floats уникальные для данного представления "неточные" значения наподобие того же 0.1 в случае binary floats?
Здравствуйте, FrozenHeart, Вы писали:
FH>А есть ли у decimal floats уникальные для данного представления "неточные" значения наподобие того же 0.1 в случае binary floats?
Наподобие 0.1 нет. Они будут получаться в результате расчетов.
P>Наподобие 0.1 нет.
А в случае binary floats они есть из-за того, что мы пытаемся провести конвертацию из десятичного представления в двоичный, верно? Т.е. к base == 2
P>Они будут получаться в результате расчетов
В двух случаях, да?
— При попытке представить конечным кол-вом знаков числа наподобие 1/3 (как это правильно назвать-то)
— При превышении точности
Здравствуйте, FrozenHeart, Вы писали:
FH>Правильно ли я Вас понял, что Вы пытаетесь донести до меня мысль о том, что decimal floats точно так же подвержены накапливаемым ошибкам, как и binary floats? Только если в случае binary floats такое сплошь и рядом (из-за того, что "неточно" представляемых чисел в нём гораздо больше -- всякие 0.1 и т.д.), то в случае decimal floats такое будет происходить хотя бы из-за превышения точности. Верно?
Ошибки связанные с "неточным" представлением в double некоторых десятичных чисел накапливаться не должны. Нужно ли для этого что-то делать в программе зависит от характера расчетов.
Здравствуйте, FrozenHeart, Вы писали:
FH>А в случае binary floats они есть из-за того, что мы пытаемся провести конвертацию из десятичного представления в двоичный, верно? Т.е. к base == 2
Да. Но в твоем случае они уже есть, "приходят" из упомянутого фреймворка
FH>- При попытке представить конечным кол-вом знаков числа наподобие 1/3 (как это правильно назвать-то)
Да
FH>- При превышении точности
При финансовых расчетов никакого превышения точности происходить не должно. Если предполагаешь, что оно при твоих расчетах он возможно, то нужно что-то делать. Для начала удостовериться, что эти опасения не на пустом месте. Затем, если это действительно так, в чем сомневаюсь, нужно увеличивать разрядность используемых представлений чисел.
P>Ошибки связанные с "неточным" представлением в double некоторых десятичных чисел накапливаться не должны
В смысле?
Вот есть, например, всё же то число 0.1, для которого binary float выбирает ближайшее представимое значение (какое-нибудь 0.10000000000000001). Если мы сложим такое число три раза, то явно получим не чистое 0.3, а что-то вроде 0.30000000000000003
FH>>А в случае binary floats они есть из-за того, что мы пытаемся провести конвертацию из десятичного представления в двоичный, верно? Т.е. к base == 2 P>Да. Но в твоем случае они уже есть, "приходят" из упомянутого фреймворка
Это да.
FH>>- При попытке представить конечным кол-вом знаков числа наподобие 1/3 (как это правильно назвать-то) P>Да
А каким термином это правильно называть, кстати, не подскажете?
FH>>- При превышении точности P>При финансовых расчетов никакого превышения точности происходить не должно.
Почему же? Представим чисто гипотетическую ситуацию.
Имеем огромный набор чисел, каждое из которых представляется при помощи binary floats с некоторой погрешностью. Если сложить их все вместе (например, для подсчёта приходов-расходов за определённый промежуток времени), вполне может накопиться такая ошибка, которая попадёт в значащие для меня разряды (например, пять знаков после запятой).
Здравствуйте, FrozenHeart, Вы писали:
FH>>>- При превышении точности P>>При финансовых расчетов никакого превышения точности происходить не должно. FH>Почему же? Представим чисто гипотетическую ситуацию. FH>Имеем огромный набор чисел, каждое из которых представляется при помощи binary floats с некоторой погрешностью. Если сложить их все вместе (например, для подсчёта приходов-расходов за определённый промежуток времени), вполне может накопиться такая ошибка, которая попадёт в значащие для меня разряды (например, пять знаков после запятой).
"Чисто гипотетически" сумма огромного набора чисел это не совсем типично для финансовых расчётов.
Если речь именно про суммирование, в значительном числе случаев помогает Kahan summation. Аналогичное можно придумать для умножения и деления, хотя и дорого
Но именно из-за таких опасений и переходят или на decimal float с контролем inexact condition, как я описывал раньше, или на fixed point.
Здравствуйте, FrozenHeart, Вы писали:
FH>А каким термином это правильно называть, кстати, не подскажете?
Не знаю. Из математики термины вспоминаются, а из IT нет
FH>Имеем огромный набор чисел, каждое из которых представляется при помощи binary floats с некоторой погрешностью.
В финансовых расчетах не бывает быть огромных наборов чисел.
FH> Если сложить их все вместе (например, для подсчёта приходов-расходов за определённый промежуток времени), вполне может накопиться такая ошибка,
Это очень небольшой набор чисел и ошибка накопится не может.
FH> которая попадёт в значащие для меня разряды (например, пять знаков после запятой).
Почему тебя интересует пять знаков после запятой?
Разумеется есть шанс нарваться на неприятности сложив тысяч 10 чисел имеющих порядок миллиардов и при этом представленных с точностью до копейки, но это странные финансовые расчеты, таких в жизни не бывает.
N>"Чисто гипотетически" сумма огромного набора чисел это не совсем типично для финансовых расчётов. N>Если речь именно про суммирование, в значительном числе случаев помогает Kahan summation. Аналогичное можно придумать для умножения и деления, хотя и дорого N>Но именно из-за таких опасений и переходят или на decimal float с контролем inexact condition, как я описывал раньше, или на fixed point.
Так, всё потихоньку встаёт на свои места, спасибо
Т.е. binary floats:
— Не могут точно представить некоторое множество дробных чисел и, как результат, могут накапливать ещё большую ошибку в результате выполнения над ними различных арифметических операций
Decimal floats:
— В отличие от binary floats, могут точно представить любую десятичную дробь
— Не могут представить определённое множество значений, получающихся в процессе выполнения арифметических операций (например, 1/3)
— Могут сигнализировать о выходе за пределы precision'а (inexact condition) при помощи специального флага или исключения
Fixed point numbers:
— Могут точно представить любое значение в пределах заданного precision'а, однако, очевидно, выполняют округление до заданного кол-ва знаков после запятой
Всё сказал правильно или всё же упустил что-то важное?
Здравствуйте, FrozenHeart, Вы писали:
FH>Правильно ли я Вас понял, что Вы пытаетесь донести до меня мысль о том, что decimal floats точно так же подвержены накапливаемым ошибкам, как и binary floats?
Не "точно так же", а даже больше. Если речь не идёт о числах, которые точно представимы в коротком виде. Например, decfloat64 от IEEE имеет ровно 16 десятичных цифр, и если считать до сотых долей цопеек, не будет проблем с операциями сложения, вычитания, умножения на целое, с любыми суммами менее триллиона — только за счёт точного представления.
Но моя мысль была чуть другая. Что если взять decfloat, включить исключение на inexact и считать что угодно, можно гарантировать, что проблемы будут опознаваться. А на операции, которые гарантированно неточны при стандартном расчёте (например, взять 1/7 часть от одного тугрика) — временно гасить генерацию исключения и не забывать чистить флаги после этого. С двоичным представлением и десятичными числами так не получится, будут постоянные ложные срабатывания. И это вторая важная причина использования именно десятичной плавучки (вплоть до аппаратной реализации, как в IBM zSeries).
FH> Только если в случае binary floats такое сплошь и рядом (из-за того, что "неточно" представляемых чисел в нём гораздо больше -- всякие 0.1 и т.д.), то в случае decimal floats такое будет происходить хотя бы из-за превышения точности. Верно?
При числах типа короткие десятичные дроби (типично для финансов) — именно так.
FH>Извините, что переспрашиваю, тема для меня кажется сложной, и я хочу убедиться, что правильно понимаю, о чём, собственно, идёт речь.
Да, inexact вообще такая штука, про которую крайне мало кто даже слышал.
Хотя, например, в Java и C# управлять им нельзя — там управление FP environment, включая условия ошибок, режимы округления и т.п., выкинули за непониманием (свалив проблемы на отдельные классы вроде BigFloat). Так что я не удивляюсь.
Здравствуйте, FrozenHeart, Вы писали:
N>>В общем случае — да, остаться на привычных binary floats. N>>Причина очень проста: base=10 ничего положительного тебе не даст (у тебя уже на входе и выходе binary) FH>Ну да, на входе и на выходе у меня binary floats, но ведь decimal floats дадут мне возможность не беспокоиться о неточном представлении чисел наподобие 0.1 и спокойно складывать их, ожидая, что 0.1 + 0.1 + 0.1 на самом деле будет равно 0.3
Это только при условии, что преобразование в этот самый decimal будет убирать уже накопленные ошибки округления.
FH>Или Вы о том, что decimal я в итоге сконструирую на основе binary float, который уже содержит эту ошибку, в связи с чем перевод из binary в decimal уже мог дать "ошибочное" значение?
Именно.
Если твёрдо известно, что вот эти числа надо округлить до 1/10000 — нет проблем. Если нет — если на входе было ~0.3000003, оно так и будет сохранено как 0.3000003 в десятичном и так и будет передаваться по цепочке расчёта.
N>>и они хуже потому, что с ростом base увеличиваются ошибки округления и дребезг значения младшего разряда. FH>С ростом base от 2 до 10?
Да.
В S/360 вообще было base16, и по ним эта проблема стуканула в полный рост (народ после IBM 704, 709, переходя на эти машины, матерился во много этажей). К тому же они в double умудрились выкинуть guard digits из промежуточных расчётов, и их так заклевали, что они в 68-м "отзывали" все машины на переделку за свой счёт. С тех пор народ знает, чем проблемны такие основания.
N>Но моя мысль была чуть другая. Что если взять decfloat, включить исключение на inexact и считать что угодно, можно гарантировать, что проблемы будут опознаваться. А на операции, которые гарантированно неточны при стандартном расчёте (например, взять 1/7 часть от одного тугрика) — временно гасить генерацию исключения и не забывать чистить флаги после этого. С двоичным представлением и десятичными числами так не получится, будут постоянные ложные срабатывания. И это вторая важная причина использования именно десятичной плавучки (вплоть до аппаратной реализации, как в IBM zSeries).
А, я-то думал, что inexact можно только для decimal floats выставлять. Вы же о функциях наподобие _controlfp_s говорите?
N>вплоть до аппаратной реализации, как в IBM zSeries
Т.е. как это? Что там аппаратно выполняется?
N>Хотя, например, в Java и C# управлять им нельзя — там управление FP environment, включая условия ошибок, режимы округления и т.п., выкинули за непониманием (свалив проблемы на отдельные классы вроде BigFloat). Так что я не удивляюсь.
Не, я в основном на C++ пишу, но вопрос общий, это да.
N>>>и они хуже потому, что с ростом base увеличиваются ошибки округления и дребезг значения младшего разряда. FH>>С ростом base от 2 до 10?
Не совсем понимаю, почему ошибки округления увеличиваются. Можно пример или какое-нибудь пояснение, пожалуйста?
Здравствуйте, FrozenHeart, Вы писали:
FH>А, я-то думал, что inexact можно только для decimal floats выставлять.
Нет.
FH> Вы же о функциях наподобие _controlfp_s говорите?
Да.
N>>вплоть до аппаратной реализации, как в IBM zSeries FH>Т.е. как это? Что там аппаратно выполняется?
Именно плавучка по основанию 10 согласно IEEE 754-2008. Основные операции с ней.
Причём представление мантиссы не двоичное, как в GCC эмуляции libdecimal, а 3-to-10 (Chen-Ho encoding), что "доставляет" тем, кто этого не видел раньше Это они продавили такое чудо в стандарт
Здравствуйте, pagid, Вы писали:
P>Здравствуйте, netch80, Вы писали:
N>>Вручную если считается в целых типа 1/100 копейки, P>Какой смысл считать в 1/100 копейки, а не в копейках?
Это не ко мне вопрос. Ряд стандартов так требуют для промежуточных значений в расчётах (на самом деле речь шла про США и центы).
Вероятно, этим как раз и решают проблемы округления промежуточных значений — не копал эту тему.
N>> то в этих целых и поддерживается (например, чтобы 100 разрезалось на 33+33+34). P>Верно, уже упоминал об этом выше. Но тоже самое придется делать и при представлении чисел другими способами.
Я говорю именно о задаче. В матфизике нет необходимости разделять число на части с точным совпадением суммы этих частей до последней значащей цифры. В финансах это обязательное условие при любой подобной операции — "итого", остатки и балансы должны сходиться точно, где вообще компьютер может этому помочь.
P>Но, например, нужно расчать что-то с участием в выражении не только денег, а каких-нибудь процентов или коээфициентов, и точность их представления нужна не 0.01 или даже не 0.0001. И получится выражение с разными типами чисел, их приведением возможно в одном выражение и вероятными проблемами. С double этой проблемы не будет. P>Вовсе не призываю использовать double в финансовых расчетах, боже упаси Просто к тому, что отказ от "неточного" представления чисел вовсе не решает всех проблем и не отменяет необходимости думать.
Верно, как и переход на флоаты не убивает эту возможность. Но усиливает необходимость думать.