Чистое устранение ошибок округления/накопления

У меня есть приложение, где я отслеживаю объемы жидкости в мкл. В настоящее время я использую «double» для хранения томов во всей системе, и в большинстве случаев это отлично работает. Однако, когда я начинаю добавлять и вычитать большое количество этих томов, начинают возникать различные ошибки накопления. Ошибки очень малы по величине, но они вызывают проблемы с пороговыми сравнениями, где внезапно объем меньше ожидаемого минимальной суммы, вызывая ошибки проверки. Я понимаю, что это довольно распространенная проблема с выполнением аккумулирования операций с плавающей запятой, но мне интересно, как лучше всего решать проблемы. Несколько мыслей, которые у меня были:

  1. Я могу заменить все мои двойные ссылки целыми числами и вместо этого отслеживать все в nL. Это, безусловно, решит проблему, но это очень инвазивные изменения. Однако система еще не используется в производстве, что означает, что ее применение теперь будет намного проще, чем пытаться применить ее позже.

  2. Я могу использовать Decimal вместо double. Это менее инвазивно, чем изменение целых чисел, но требует значительных изменений.

  3. Я могу потребовать, чтобы все сравнения томов допускали заданную погрешность. Это в основном то, что я делаю прямо сейчас, но это делает код сравнения более уродливым, и он требует некоторого обзора кода, чтобы убедиться, что никто не забывает применить шаблон.

  4. Я могу выполнить округление до заданного допуска после каждого вычисления, чтобы предотвратить накопление ошибок. Это делает сравнение более чистым, но теперь у него есть аналогичная проблема, везде есть назначения.

Для тех, кто также боролся с этой проблемой, какие решения оказались самыми чистыми для реализации? Есть ли другие проблемы, о которых я должен знать при выполнении аккумулирующих расчетов?

6
nl ja de
Мой голос - интегральный тип - возможно, завернутый, как предлагает Алексей.
добавлено автор Daniel Hilgarth, источник
Вы почти наверняка не хотите делать # 4, # 3 гораздо предпочтительнее. # 4 дает каждой операции возможность еще большей ошибки, чем у вас в настоящее время, что может быть очень плохо.
добавлено автор Servy, источник
Замечание: если вы решили заменить double чем-нибудь - рассмотрите собственный класс вместо decimal / long . Стоимость кодирования будет примерно одинаковой, но вы будете контролировать представление и можете блокировать непреднамеренные преобразования для обычных числовых типов, просто не предоставляя никаких автоматических преобразований.
добавлено автор Alexei Levenkov, источник

1 ответы

В идеале вы хотите

  • используйте тип данных, который не подвержен ошибкам округления (аппроксимации), и
  • округление до нужного числа знаков после запятой
  • в нужное время.

Вам не нужен большой диапазон плавания с двойной точностью. Вы вероятно не хотите использовать целые числа. Они немного быстрее, но использование их более сложно. Используйте числовое или десятичное число. Числовые и десятичные типы данных не подвержены ошибкам округления или ошибкам аппроксимации. Но вы все еще не можете быть небрежным или небрежным в своем программировании; присвоение числового значения переменной типа double приведет к возврату проблемы.

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

Иногда то, что люди называют ошибкой округления , действительно является приближенной ошибкой . Если вы скажете компьютеру хранить десятичное значение r в столбце переменной или столбце с плавающей запятой, оно фактически сохранит приближение с плавающей запятой к r .

Каноническая ссылка для арифметики FP

2
добавлено
Спасибо за интересную ссылку; катастрофическое аннулирование особенно интересно, так как у меня есть места в моем коде, где я решаю квадратичные корни. Я понятия не имел, насколько сильно на точность может влиять порядок расчета.
добавлено автор Dan Bryant, источник
Я запустил изменение всех ссылок на объем, чтобы использовать десятичную и хорошо разрешенные вещи. Он требует явного преобразования в double в C#, поэтому он делает его очень понятным во всем коде, где пересекается граница преобразования. Это означало создание множества дублированных функций математического помощника, которые работают на десятичной основе вместо двух, но это разумные накладные расходы, чтобы предотвратить накопление ошибок.
добавлено автор Dan Bryant, источник
Кнуту есть что сказать об этом в TAOCP, том 2.
добавлено автор Mike Sherrill 'Cat Recall&, источник
DotNetRuChat
DotNetRuChat
2 992 участник(ов)

Чат русскоязычного .NET сообщества http://dotnet.ru/ Вам могут быть интересны: @dotnetchat, @cilchat, @fsharp_chat, @pro_net, @xamarin_russia, @microsoftstackjobs, @uwp_ru Флуд в @dotnettalks

Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

pro.net
pro.net
710 участник(ов)

Обсуждение .NET Framework и всего, что с ним связано. Правила: не флудить не по теме, уважать ваших коллег и никакой рекламы (объявления о вакансиях можно согласовать с @AlexFails). Флудилка: @dotnettalks Участник @proDOT

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot

.NET Talks: Force Push Masters
.NET Talks: Force Push Masters
490 участник(ов)

Свободный чат .NET разработчиков. Правила: t.me/dotnettalks/56823 Вам могут быть интересны: @dotnetruchat, @dotnetchat, @cilchat, @fsharp_chat, @pro_net, @dotnetgroup, @xamarin_russia, @microsoftstackjobs, @uwp_ru http://combot.org/chat/-1001128250813

.NET Chat Убежище
.NET Chat Убежище
246 участник(ов)

Чат .NET разработчиков под эгидой MSK/SPB .NET Community Group Вам могут быть интересны: @fsharp_chat, @dotnetruchat, @cilchat, @xamarin_russia, @microsoftstackjobs, @dotnetgroup Флуд в @dotnettalks

.NET CIL Chat
.NET CIL Chat
54 участник(ов)

.NET CIL (aka IL aka MSIL)