2

The following class just has one method that returns the divisor of a certain percent, so if I pass it 5, it will return 0.05.

public class Adjustment
{
    public decimal Amount {get;set;}
    public bool IsCompounded {get;set;}
    public bool Add{get;set;}

    public decimal Calculate(decimal amount)
    {
        return (amount / 100.0M);
    }
 }

My main method is defined as follows:

void Main()
{

    Adjustment a1 = new Adjustment {Amount = 10.0M, IsCompounded = false, Add = true};
    Adjustment a2 = new Adjustment {Amount = 7.0M, IsCompounded = false, Add = true};


    List<Adjustment> adjustments = new List<Adjustment>();
    adjustments.Add(a1);
    adjustments.Add(a2);

    decimal value = 0.0M;
    decimal total = 100.0M;

    foreach(Adjustment a in adjustments)
    {
        if(a.IsCompounded)
        {
            value = (1 + a.Calculate(a.Amount));

            if(a.Add)
                 total *= value;
            else
                total /= value;
        }
        else if(!a.IsCompounded)
        {
             value += a.Calculate(a.Amount);

             if(a.Add)
                 total *= value;
         else
                 total /= value;
        }
    }

    Console.WriteLine(total);
}

In the above main method, I am starting off with 100 as the total and if all the taxes are compounded, it works fine, I get 117.7 and if I take 117.7 and remove the taxes, I get back to 100. For non compounded, I only need to add 1 to the very end and then divide the total by that, but I am not sure how to do it. Currently, when I am looping through, I am just adding the divisors, for example 0.1 + 0.07 = 0.17. Outside the loop, I need to add 1 to that to get 1.17 and then multiply or divide the total to either add or remove the tax respectively. Then there is the issue of the adjustments being compounded and non-compounded which gets more complicated. In this case, I need to do something like the following:

For example, Assume I have 3 taxes, 10, 7, and 3. 10 and 7 are compounded and 3 is non-compounded, so the formula is:

100 * (1+((1+0.10) * (1+0.07)−1)+((1+0.03)−1)) which simplifies to 100 * ((1+0.10) * ( (1+0.07)+0.03) = 120.70

I am not sure how to implement the above.

Xaisoft
  • 45,655
  • 87
  • 279
  • 432

2 Answers2

0

If I understand your requirements correctly, I think you just need to keep separate compounded and non-compounded fractions as you iterate through the Adjustments and just combine them at the end.

decimal total = 100.0M;

decimal compounded = 1.0M;
decimal nonCompounded = 0.0M;
foreach(Adjustment a in adjustments)
{
    if(a.IsCompounded)
    {
        decimal value = (1.0m + a.Calculate(a.Amount));

        if (a.Add)
            compounded *= value;
        else
            compounded /= value;
    }
    else
    {
        decimal value = a.Calculate(a.Amount);

        if (a.Add)
            nonCompounded += value;
        else
            nonCompounded -= value;
    }
}

if (nonCompounded >= 0)
{
  total *= (compounded + nonCompounded);
}
else
{
  total *= (compounded / (1.0m - nonCompounded));
}

Will you only ever pass a.Amount into a.Calculate? You could read the amount from the object then, e.g.

public decimal Calculate()
{
    return (Amount / 100.0M);
}

or you could make this a property get instead, e.g.

public decimal AmountFraction
{
    get
    {
        return (Amount / 100.0M);
    }
}

which you'd then read as decimal value = a.AmountFraction; i.e. as a property not a function call.

Edit: modified the combination line to remove non-compounded fractions as per comments.

Rup
  • 33,765
  • 9
  • 83
  • 112
  • As of right now, I am just passing in a.Amount. I am little confused by the second part of your statement: You read the amount from the object then and maybe return it as a property get instead. – Xaisoft Apr 14 '11 at 17:02
  • OK, hope that makes more sense! – Rup Apr 14 '11 at 17:08
  • I think I get it, so I should put the property AmountFraction inside my Adjustment class, correct? I will test the remainder of your code and let you know how it goes. – Xaisoft Apr 14 '11 at 17:10
  • Curious, by calling a.AmountFraction, is it faster, I wouldn't think so because it is calling the same code. – Xaisoft Apr 14 '11 at 17:12
  • Yes, that's where I meant. However it won't make any difference to the code that's actually generated or efficiency or anything (metadata aside) - it's still a function call under the covers, it's just a style option. I'm sure it can't be faster?? Or at least it shouldn't make any significant difference. – Rup Apr 14 '11 at 17:12
  • When I take your code and put in 100 and added non-compounded tax, it return 117, which is correct, however, when I remove the non-compounded tax from 117, it returns 97.110, which is incorrect, it should return 100. – Xaisoft Apr 14 '11 at 17:14
  • That's removing 17% of the 117, which is what I assumed you meant by that removal. OK, if you want 100 instead then how do you want to combine non-compounded adds and removals in the same calculation? – Rup Apr 14 '11 at 17:19
  • OK, that might be what you want. But if you're stuck on what the combining rules should be then you should talk to whoever's given you the specification for your task - ultimately it's what they want that counts! – Rup Apr 14 '11 at 17:25
  • no, what i am saying is that I know the rules. As I stated in my post, I have the add and removal of compounded taxes correct. With non-compounded, I just need to add a 1 to the very end, not on each iteration. And as far as mixing them, I am not sure what to do as far as implementation. – Xaisoft Apr 14 '11 at 17:31
  • Your code is working, but one thing I am not sure is if I remove the taxes, I have to do divide by the total and if I add the taxes I have to multiply, but I can't check a.Add outside the loop and I wouldn't want to do an inner loop in case it is necessary in this case? – Xaisoft Apr 14 '11 at 17:50
  • If you're removing compound taxes then I'm dividing the compounded-fraction-so-far in the loop and multiplying the total by that fraction at the end should work. For a net removal of non-compounded taxes I've now turned the combination step into a division (d'oh - obviously I could could remove the `* 1.0m` from my code) which ought to work too. – Rup Apr 14 '11 at 17:53
  • If the tax is non-compounded, I don't think you need nonCompounded -= value, I believe all you need is nonCompounded += value; Secondly, when you are calculating the total if you want to add tax, you need to do total *= compounded + nonCompounded, but if I want to remove tax, I need to do total /= (compounded + nonCompounded). The problem here is how do I check if I shoudld remove it if the a.Add is out of scope. – Xaisoft Apr 14 '11 at 18:08
  • I think that's only true if all of the a.Add are the same. I'm attempting to do it in a way that lets you mix adds and removals. But if you can guarantee that they're all the same then you can probably just test `adjustments.First().Add` (assuming you have can use LINQ and that adjustments has at least one value) and decide based on that. – Rup Apr 14 '11 at 18:17
  • This is a link I originally posted on Math.StackExchange.com: http://math.stackexchange.com/questions/32854/adding-and-removing-non-compounded-percentages-does-not-produce-the-same-result – Xaisoft Apr 14 '11 at 18:37
0

Try this:

public class Adjustment
{
    public decimal Amount {get;set;}
    public bool IsCompounded {get;set;}
    public bool Add{get;set;}

    public decimal Calculate()
    {
        if(IsCompounded)
            return 1 + Amount / 100.0M;
        else
            return Amount / 100.0M;
    }
 }

void Main()
{
    List<Adjustment> adjustments = new List<Adjustment>();
    adjustments.Add(new Adjustment() {Amount = 10.0M, IsCompounded = false, Add = true});
    adjustments.Add(new Adjustment() {Amount = 7.0M, IsCompounded = false, Add = true};);

    decimal value = 0.0M;
    decimal total = 100.0M;

    foreach(Adjustment a in adjustments)
    {
        value = a.Calculate();

        if(a.IsCompound)
        {
            if(a.Add)
                 total *= value;
             else
                 total /= value;
        }
        else
        {
            if(a.Add)
                 total += value; //should be a sum for nom-compounded
             else
                 total -= value;
        }
    }

    Console.WriteLine(total);
}
Ortiga
  • 8,455
  • 5
  • 42
  • 71
  • This does not work, you are just adding 100 + 0.17 to get 100.17. The formula for non-compounded is 100 * (1 + 0.10 + 0.07) in this case. – Xaisoft Apr 14 '11 at 17:07