Как насчет этого (см. Встроенные комментарии для описания алгоритма):
let handoutMoney totalAmount allocations minAmount =
//the general approach is to start off giving each party the
//minAmount, and then from there dividing up the remaining
//totalAmount proportionally by allocation for those parties
//that have not exceeded their original allocation
//with respect to minAmount, map under-allocated as Some,
//and over-allocated as None
let underAllocated =
allocations
|> Array.map (fun pct ->
if pct * totalAmount > minAmount then Some(pct) else None)
//Sum all the under-allocated percentages, we will use this
//to recalculate percentages for remaining allocations beyond
//the minAmount
let remainingAllocationTotal =
underAllocated
|> Array.sumBy (function | Some(pct) -> pct | None -> 0.0M)
//Now using the remainingAllocationTotal we can adjust the
//underAllocated allocations so that the remaining amount
//after the min amount is subtracted can be proportionally allocated
let remainingAllocations =
underAllocated
|> Array.map (function
| Some(pct) -> (pct / remainingAllocationTotal)
| None -> 0.0M)
//the amount leftover from the totalAmount after the subtracting
//the minAmount which was given to each party
let remainingAmount =
totalAmount - (minAmount * decimal allocations.Length)
//tie it all together: add the minAmount to the remainingAllocation
//pct times the remainingAmount
remainingAllocations
|> Array.map (fun pct ->
minAmount + (pct * remainingAmount))
Тогда, учитывая ваш пример, мы получили бы:
> handoutMoney totalAmount allocations minAmount;;
val it : decimal [] =
[|575.00000000000000000000000000M; 575.00000000000000000000000000M; 250.0M|]
(Я не совсем уверен, откуда вы взяли 500 долларов, выделяемых стороне A & B в вашем примере, но я считаю, что алгоритм, который я представил, является разумным подходом к проблеме, насколько я понимаю)