У меня есть проблема, которую можно свести к этой постановке задачи:
Учитывая серию пар, где каждый находится в диапазоне [0, 1e7]
,
изменить последний элемент так, чтобы сумма чисел равнялась
точно целевое число. Серия двойников уже суммируется с
число цели в эпсилоне (1e-7), но они не ==.
Следующий код работает, но гарантированно ли он работает для всех входных данных, которые отвечают требованиям, описанным в первом предложении?
public static double[] FixIt(double[] input, double targetDouble)
{
var result = new double[input.Length];
if (input.Length == 0) return result;
double sum = 0;
for (int i = 0; i < input.Length - 1; i++)
{
sum += input[i];
result[i] = input[i];
}
double remainder = targetDouble - sum;
result[result.Length - 1] = remainder;
return result;
}
var arr1 = Enumerable.Repeat(Math.PI / 13, 13).ToArray();
var arr2 = FixIt(arr1, Math.PI);
Debug.Print(Math.PI.ToString("R")); //3.1415926535897931
Debug.Print(arr1.Sum().ToString("R")); //3.1415926535897922
Debug.Print(arr2.Sum().ToString("R")); //3.1415926535897931
В предыдущей версии этого вопроса задавался вопрос об изменении первого элемента, но изменение последнего элемента упрощает задачу до известной суммы и известной цели, оставляя нам только вопрос о том, подразумевает ли last = target-sum
, что sum+last == target
.
(Конечно, без NaN, а ограничения на диапазоны подразумевают некоторые ограничения на last
, что также может помочь.)
Относительно реальной проблемы: эта проблема возникала несколько раз различными способами, но в настоящее время мы пытаемся уменьшить ошибку с плавающей запятой, возникающую из-за числовых значений нестабильности в решателе линейного программирования (Coin-OR CBC). Например, есть 6 переменных, которые все должны находиться в диапазоне [0, X], а сумма переменных также должна быть X. Из-за нестабильности чисел решатель иногда возвращает слегка отрицательные значения и значения, которые не суммируются точно X. Мы преодолели проблему отрицательных чисел - теперь просто пытаемся решить проблему суммы X. (Да, могут быть ограничения, которые мы не выполняем, изменяя результаты, но убедившись, что сумма этих чисел к X имеет более высокий приоритет, где другие ограничения не так важны.)