문제

부서 1..N에 할당 해야하는 비용 C가 있습니다. 또 다른 계산은 각 부서의 점유율을 생성하며, 0에서 1까지의 숫자이며, 10 진수 자리가 5 개 이상입니다. 모든 부서 주식의 합은 정확히 1이지만 반드시 같을 필요는 없습니다.

목표는 정확한 달러와 센트를 각 부서에 청구하는 것을 계산하는 것입니다. 청구서의 합은 비용 C와 정확히 일치해야하며, 몇 개의 동전이 될 수는 없습니다. 또한 각 부서의 비중은 분수 동전이 필요하지 않아야합니다. 또한 나머지 부서를 마지막 부서에 버리는 것은 공정하지 않지만 이전 기간을 되돌아 볼 필요는 없습니다. 단순히 각 부서의 지분을 페니에 반올림하면 거의 항상 몇 개의 동전의 오버/아래에 있습니다.

크게 지나치게 단순화 된 예 : C = 33.34, 각각 정확히 0.2500 점유율의 부서. 33.34 * 0.25 = 8.335이므로 두 부서가 8.33을 지불해야하고 두 부서는 8.34를 지불해야한다는 것을 알 수 있습니다. 올바른 할당은 다음과 같습니다. D1 = 8.33, D2 = 8.34, D3 = 8.33, D4 = 8.34입니다. 당신이 반올림하는 경우, 모든 부서는 8.34를 지불하여 $ 0.02의 초과를 초과합니다. 더 많은 부서와 더 많은 비용을 곱하면 수백 달러의 불일치로 끝납니다.

나는 1 패스로 이것을하고 싶다. 즉, 나는 루프를 통과하고 싶지 않다. 나는 0.02에 의해 꺼져 있다는 것을 알게 된 다음 다시 루프하고 그것이 올바른 값을 조정한다. 1 패스로 이것을하고 싶습니다. 이 알고리즘에 이름이 있는지 알고 싶습니다.

도움이 되었습니까?

해결책

Perl에서 :

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

use List::AllUtils qw( sum );

print Dumper allocate(10_000, .23, .37, .4);
print Dumper allocate(33.34, .25, .25, .25, .25);
print Dumper allocate(100, 1/3, 1/3, 1/3);

sub allocate {
    my ($C, @shares) = @_;

    my @alloc;

    while ( my $share = shift @shares ) {
        push @alloc, sprintf '%.2f', $C * $share;
        $C -= $alloc[-1];
        my $denom = sum @shares;
        $_ /= $denom for @shares;
    }

    return \@alloc;
}

산출:

$VAR1 = [
          '2300.00',
          '3700.00',
          '4000.00'
        ];
$VAR1 = [
          '8.34',
          '8.33',
          '8.34',
          '8.33'
        ];
$VAR1 = [
          '33.33',
          '33.34',
          '33.33'
        ];

다른 팁

플로트를 사용하지 마십시오. 고정점 소수점 숫자를 사용하거나 ints를 사용하여 스케일링 계수로 값을 달러로 얻는 것이 무엇이든 나눌 수 있습니다.

절대로, 항상 플로트를 사용하여 돈을 계산하십시오.

나는 이것을 "Total Runing"이라고 부르고 다음과 같이 구현하겠습니다.

  1. 부서 #1이 빚진 주식을 계산합니다 (반올림 오류가있을 수 있음)
  2. 1 단계에서 계산 된 금액을 지불하는 부서 #1을 지불하십시오.
  3. 부서 1과 부서 #2가 공동으로 빚진 주식을 계산하십시오.
  4. Dept #1을 3 단계에서 계산 된 금액을 지불하십시오.
  5. #S 1, 2 및 3에 의해 공동으로 빚진 금액.

이렇게하면 모든 부서에서 경험 한 오류가 최대 하나의 반올림 오류 (여러 반올림 오류의 합이 아님)이며 최종 총계가 정확하도록합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top