@fiter

Как избавиться от погрешности при делении суммы?

Дана сумма в рублях - $totalProfit = (float) 12.50
Нужно поделить эту сумму между правообладателями. У меня так получается, что после разделения сумма получившихся частей равняется 12.51, т.е. появляется лишняя копейка. Нужно это исправить.
Есть 4 типа правообладателей, между ними делится вся сумма:
public $percentage = [
        1 => 0.2, // Authors
        2 => 0.2, // Composers
        3 => 0.3, // Performers
        4 => 0.3  // Producers
    ];

В свою очередь, внутри этих типов идёт распределение между правообладателями. Допустим, есть 2 правообладателя Authors, у первого $this->percent = 25, у второго $this->percent = 75, доля для каждого из них вычисляется так:
round( $totalProfit * $this->percentage[ $this->rightholder_type_id ] * ( $this->percent/100 ), 2 )
  • Вопрос задан
  • 524 просмотра
Решения вопроса 1
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Обычно в финансах работают с целыми числами, представляющими собой тысячные (иногда и десятитысячные) доли рубля. Доли, по возможности, представляют натуральными дробями. В этом случае ваша задача преобразуется из (12.50 * 0.2) в (12500 * 2 / 10). При целочисленных вычислениях минимизируется погрешность самих расчётов.

Следующая проблема - округление до целых копеек при сложении. Если мы получили 0.3 и 0.4 копейки (3 и 4 в тысячных долях рубля), то при их округлении получим 0.3 ≈ 0 и 0.4 ≈ 0, а при округлении их суммы получим 0.3 + 0.4 = 0.7 ≈ 1. То есть в результате будет 0 + 0 = 1.
Для решения такой проблемы применяют системное округление. Сначала все слагаемые округляются с отбрасыванием дробной части, а их сумма округляется по общим правилам. Вычтя из округлённой суммы сумму округлённых слагаемых получим количество единиц, которые надо раскидать. Затем исходные слагаемые сортируются по убыванию дробной части и соответствующее их количество округляется вверх.

Скажем слагаемые у нас 1.6, 2.7 и 3.8.
Их сумма 1.6 + 2.7 + 3.8 = 8.1
Если округлить слагаемые по общим правилам, то получим 2 + 3 + 4 = 9 ≠ 8
Округляем их с отбрасыванием: 1 + 2 + 3 = 6
Округлённая сумма 8.1 ≈ 8
8 - 6 = 2, значит два слагаемых с наибольшей дробной частью надо округлить вверх.
3.8 ≈ 4, 2.7 ≈ 3, 1.6 ≈ 1
4 + 3 + 1 = 8
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
lxsmkv
@lxsmkv
Test automation engineer
echo round(9.375, 2);  // 9.38 
echo round(9.375, 2, PHP_ROUND_HALF_DOWN); //9.37
Ответ написан
KorniloFF
@KorniloFF
Работаю по font-end / JS
Math.round((1.5+2.25)*100)/100
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы