Ваш конечный результат представляет собой средневзвешенное значение точности, поэтому, по-видимому, вам не нужно следовать правилам, используемым при расчете остатков на счетах и т. Д. Если я прав в отношении вышеизложенного, вам не нужно использовать BigDecimal
, double
будет достаточно.
Проблема переполнения может быть решена путем сохранения «скользящего среднего» и обновления его с каждой новой записью. А именно пусть
a_n = (sum_ {i = 1} ^ n x_i * w_i) / (sum_ {i = 1} ^ n w_i)
для n = 1, ..., N. Вы начинаете с a_n = x_n, а затем добавляете
d_n: = a_ {n + 1} - a_n
к нему. Формула для d_n:
d_n = (x_ {n + 1} - w_ {n + 1} * a_n) / W_ {n + 1}
где W_n: = sum_ {i = 1} ^ n w_n. Вам необходимо отслеживать W_n, но эту проблему можно решить, сохранив ее как double
(все будет в порядке, поскольку нас интересует только среднее значение). Вы также можете нормализовать веса, если вы знаете, что все ваши веса кратны 1000, просто разделите их на 1000.
Для получения дополнительной точности вы можете использовать скомпенсированное суммирование .
Упреждающее объяснение: здесь можно использовать арифметику с плавающей запятой. double
имеет относительную точность 2E-16. ОП усредняет положительные числа, поэтому ошибки отмены не будет. Сторонники арифметики произвольной точности не говорят вам, что, оставляя в стороне правила округления, в случаях, когда делает , дает вам большую дополнительную точность по сравнению с арифметикой IEEE754 с плавающей запятой, это придет к значительной памяти и стоимость исполнения. Арифметика с плавающей запятой была разработана очень умными людьми (проф. Кахан, среди прочих), и если бы был способ дешевого повышения арифметической точности по сравнению с тем, что предлагает с плавающей запятой, они сделали бы это.
Отказ от ответственности: если ваши веса абсолютно сумасшедшие (один равен 1, другой - 10000000), то я не уверен на 100%, если вы получите удовлетворительную точность, но вы можете проверить это на некотором примере, когда вы знаете, какой ответ должен быть будет.