2009-12-01 55 views
1

我們有成本C,必須分配給部門1..n。另一個計算會生成每個部門的份額,它是一個從0到1的數字,並且有5個以上的小數位。所有部門份額的總和恰好是1,但它們不一定相等。準確的單程便士計算

目標是計算確切的美元和美分賬單給每個部門。賬單的總和必須完全匹配成本C,不能少於幾個便士。此外,每個部門的份額必須不要求分數便士。此外,儘管將剩餘部分轉儲到最後一個部門是不公平的,但沒有必要回顧以前的時間框架。請注意,簡單地將每個部門的份額四捨五入到幾乎一分錢總是會導致幾個便士的大小。

嚴重過於簡單的例子:C = 33.34,4個部門,每個部門都有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' 
     ]; 
+0

我想我明白了這一點,謝謝 – user130582 2009-12-01 02:41:30

2

請勿使用浮筒。使用固定點十進制數,或使用整數,這樣就可以除以任何縮放因子來獲得以美元爲單位的值。

從來沒有,有史以來使用花車計算錢。

1

我會叫它 「運行總計」,並按如下實現它:

  1. 計算佔有率部門拖欠#1(可能有舍入錯誤)
  2. 使部門#1支付計算的金額在步驟1
  3. 計算多數民衆贊成聯合部門#1和#部門所欠的份額2
  4. 製作部門#1支付在第3步計算的金額,減去在步驟2中
  5. 等,爲實際支付的金額共同欠部門#1,2和3.

這將確保任何部門經歷的錯誤至多是一個舍入誤差(不是幾個舍入誤差的總和),並且最後的總數是正確的。