Десятичный порядок сложения влияет на результаты - PullRequest
5 голосов
/ 03 июня 2011

У меня есть система, которая выполняет много вычислений с использованием десятичных дробей, иногда она складывает одинаковые числа, но возвращает разные результаты, +/- 0,000000000000000000000000001

Вот краткий пример:

decimal a = 2.016879990455473621256359079m;
decimal b = 0.8401819425625631128956517177m;
decimal c = 0.4507062854741283043456903406m;
decimal d = 6.7922317815078349615022988627m;

decimal result1 = a + b + c + d;
decimal result2 = a + d + c + b;

Console.WriteLine((result1 == result2) ? "Same" : "DIFFERENT");
Console.WriteLine(result1);
Console.WriteLine(result2);

Что выводит:

DIFFERENT
10.100000000000000000000000000
10.100000000000000000000000001

Различия настолько малы, что практического эффекта нет, но кто-нибудь видел что-то подобное раньше?Я ожидал, что при сложении одинаковых чисел вы всегда получите одинаковые результаты.

Ответы [ 5 ]

8 голосов
/ 03 июня 2011

Все поле Числовой анализ посвящено изучению таких эффектов и способов их предотвращения.

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

3 голосов
/ 03 июня 2011

Вы можете подозревать, что тип decimal невосприимчив к отравлению double -пользователей повсюду.

Но , поскольку decimal имеет 28-29 цифр точности ваш ввод запрашивает сумму точности в 29 цифр данных, вы на самом краю того, что может точно представлять ваш тип данных.

2 голосов
/ 03 июня 2011

Согласно по MSDN точность десятичного числа составляет 28-29 цифр. По крайней мере один из ваших номеров состоит из 29 цифр, поэтому вы, вероятно, превышаете лимит.

0 голосов
/ 03 июня 2011

Из-за округления результат суммирования для нескольких чисел может варьироваться в зависимости от порядка их суммирования.Это не произойдет в математике, но способ вычисления суммы в вашем примере имеет значение.result += number; суммирует и сохраняет результат в переменной результата.В это время часть точности теряется.Однако, если мы сделаем это в одном и том же порядке, это всегда приведет к одному и тому же результату.

Console.WriteLine(numbers.Sum()); // Always returns 9.214085249270111332166335344

Из-за этого многие программы используют округление по шкале Банкерса, которое дает более близкие результаты.Пожалуйста, знайте, что точность всегда теряется.Невозможно сохранить «точное» число с плавающей запятой в памяти компьютера

Округление

Банковское округление

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...