坚持从一个值中删除/添加多个税?

时间:2011-04-27 13:25:44

标签: c# finance

我必须从值中删除/添加多个税或调整以返回到应用它的原始值。我将定义调整的内容:

调整可以是复合或非复合的百分比。它也可以是一笔不变的金额。它也可以添加或删除到初始值。我只需要编写从税后价值中反转税收的部分。我写了一些我可以用来生成测试数据的东西,我写了一些其他的东西,可以从测试数据生成的税后价值中反转这些调整。我认为我过度工程应用调整并取消应用。调整是应用顺序,所以包含(+ 7%非复合,+ 3%复合,+ 5%非复合)的列表将首先应用7,然后是3然后是5,在这种情况下,我相信要删除它我必须倒退,意味着删除5,然后删除3,然后删除7.这是我的程序将调整应用于初始值(它应该带回115.21,但在这种情况下它会带回来115.0)

void Main()
{
Adjustment a1 = new Adjustment {Amount = 7.0M, IsCompounded = false, Add = true, Percent = true};
Adjustment a2 = new Adjustment {Amount = 3.0M, IsCompounded = true, Add = true, Percent = true};
Adjustment a3 = new Adjustment {Amount = 5.0M, IsCompounded = false,  Add = true ,Percent = true};



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


decimal total = 100m;

decimal adjustedTotal = total;

decimal nonCompoundValues = 0.0m;
string prevTypeCalc = "";
decimal compoundValues = 1.0m;
decimal percents = 1.0m;

int i = 0;

foreach(Adjustment a in adjustments)
{
    if(a.Percent)
    {
        if(a.IsCompounded)
        {
            if(a.Add)
            {
                compoundValues *= a.CompoundedValue;
            }
            else
            {
                compoundValues /= a.CompoundedValue;
            }

            prevTypeCalc = "Compound";
        }
        else if(!a.IsCompounded)
        {
            if(a.Add)
            {
                nonCompoundValues += a.AmountFraction;
            }
            else
            {
                nonCompoundValues -= a.AmountFraction;
            }

            prevTypeCalc = "Non-Compound";
        }
    }
    else
    {

        if(prevTypeCalc == "Non-Compound" || prevTypeCalc == "Compound")
        {
            if(nonCompoundValues <= 0)
                adjustedTotal *= compoundValues - Math.Abs(nonCompoundValues);
            else
                adjustedTotal *= compoundValues + Math.Abs(nonCompoundValues);

            compoundValues = 1.0m;
            nonCompoundValues = 0.0m;   
        }

        if(a.Add)
        {   
            adjustedTotal += a.Amount;
        }
        else
        {
            adjustedTotal -= a.Amount;
        }

        prevTypeCalc = "Flat";

    }
}

if(prevTypeCalc == "Non-Compound" || prevTypeCalc == "Compound")
{

    if(nonCompoundValues <= 0)
        adjustedTotal *= compoundValues - Math.Abs(nonCompoundValues);
    else
        adjustedTotal *= compoundValues + Math.Abs(nonCompoundValues);
}

Console.WriteLine(adjustedTotal);

}


public class Adjustment
{
public bool Percent {get;set;}
public decimal Amount {get;set;}
public bool IsCompounded {get;set;}
public bool Add{get;set;}
public decimal AmountFraction
{
get {
    return Amount/100.0M;
}
}
public decimal CompoundedValue
{
    get{
        return 1 + AmountFraction;
    }
}
}

以下是取消应用先前算法的调整的算法。注意,当我将它们添加到列表中时,我已经颠倒了顺序,所以当我拿到115.21时,我会回到100:

 void Main()
 {
Adjustment a1 = new Adjustment {Amount = 7.0M, IsCompounded = false, Add = false, Percent = true};
Adjustment a2 = new Adjustment {Amount = 3.0M, IsCompounded = true, Add =false, Percent = true};
Adjustment a3 = new Adjustment {Amount = 5.0M, IsCompounded = false, Add = false, Percent = true};


List<Adjustment> adjustments = new List<Adjustment>();

adjustments.Add(a3);
adjustments.Add(a2);
adjustments.Add(a1);

decimal total = 115.21m;
int i = 0;
decimal adjustedTotal = total;

decimal nonCompoundValues = 0.0m;
string prevTypeCalc = "";
decimal compoundValues = 1.0m;
bool nonCompoundFirst = true;
bool first = true;
foreach(Adjustment a in adjustments)
{
    if(a.Percent)
    {
        if(a.IsCompounded)
        {
            if(a.Add)
            {
                compoundValues *= a.CompoundedValue;
            }
            else
            {
                if(prevTypeCalc == "")
                compoundValues = a.CompoundedValue;
                else
                compoundValues /= a.CompoundedValue;
            }

            prevTypeCalc = "Compound";
        }
        else if(!a.IsCompounded)
        {
            if(a.Add)
            {
                nonCompoundValues += a.AmountFraction;
            }
            else
            {
                nonCompoundValues -= a.AmountFraction;
            }


            prevTypeCalc = "Non-Compound";

        }
    }
    else
    {

    if(prevTypeCalc == "Non-Compound" || prevTypeCalc == "Compound")
    {
        if(nonCompoundValues <= 0 && compoundValues != 1) //Non-Compound
            adjustedTotal *= compoundValues + Math.Abs(nonCompoundValues);
        else if(nonCompoundValues <= 0 && compoundValues == 1) //Compound
            adjustedTotal /= compoundValues + Math.Abs(nonCompoundValues);
        else
            adjustedTotal /= compoundValues - Math.Abs(nonCompoundValues); //Compound + Non-Compound

        compoundValues = 1.0m;
        nonCompoundValues = 0.0m;   
    }

    if(a.Add)
        adjustedTotal += a.Amount;
    else
        adjustedTotal -= a.Amount;

        prevTypeCalc = "Flat";
    }
}

if(prevTypeCalc == "Non-Compound" || prevTypeCalc == "Compound")
{
    if(nonCompoundValues <= 0 && compoundValues != 1) 
        adjustedTotal /= compoundValues + Math.Abs(nonCompoundValues);
    else if(nonCompoundValues <= 0 && compoundValues == 1) //Non-compound
        adjustedTotal /= compoundValues + Math.Abs(nonCompoundValues);
    else
        adjustedTotal /= compoundValues - Math.Abs(nonCompoundValues); 


}

Console.WriteLine(adjustedTotal);

}


public class Adjustment
{
public bool Percent {get;set;}
public decimal Amount {get;set;}
public bool IsCompounded {get;set;}
public bool Add{get;set;}
public decimal AmountFraction
{
get {
    return Amount/100.0M;
}
}
public decimal CompoundedValue
{
    get{
        return 1 + AmountFraction;
    }
}
}

我遇到的主要问题是,如果所有的调整都是复合的,或者如果它们都是非复合的或者它们都是平坦的,那么我可以让它工作,但当我开始混合化合物和非化合物时它会变得疯狂百分比,我可以添加或删除它们,例如(+ 5%非化合物,-2 $,-3%化合物,+ 4%非化合物)

根据初始金额删除或添加非复合税,因此如果您的初始金额为100且您的非复合税为+ 3%和-4%,则首先添加3%的100%以获得103然后你从103减去4的100%得到99。

如果4%被复合,你将从103而不是100中取4%,所以它会是:

103 / 1.04 = 99.03846 .....

基于Lasse答案的情景:

添加所有非复合百分比 减去所有非复合百分比通过 添加所有复合百分比通过 添加所有固定金额通行证。 减去所有固定金额通行证 添加非化合物/化合物百分比通过。

减去所有复合百分比失败:

使用-7%, - 3%, - 5%。用计算器:

100 / 1.07 / 1.03 / 1.05 = 86.41511227483462,但我得到85.6995000

减去非化合物/化合物失败:

使用-7%化合物,-3%非化合物,-5%化合物,计算器:

((100 / 1.07) - 3)/ 1.05 = 86.1504 ......,但我得到85.50000。

基本上,当我将复合/非复合与添加和减去数量混合时,它开始没有产生正确的结果。

未通过的调整:

var adjustments = new Adjustment[]
{
    new CompoundTaxAdjustment(-7M),
    new CompoundTaxAdjustment(-3M),
    new CompoundTaxAdjustment(-5M)
};

var adjustments = new Adjustment[]
{
    new CompoundTaxAdjustment(+7M),
    new CompoundTaxAdjustment(-3M),
    new CompoundTaxAdjustment(-5M)
};

var adjustments = new Adjustment[]
{
    new CompoundTaxAdjustment(+7M),
    new NonCompoundTaxAdjustment(-3M),
    new CompoundTaxAdjustment(5M)
};

var adjustments = new Adjustment[]
{
    new CompoundTaxAdjustment(+7M),
    new FlatValueAdjustment(-3M),
    new CompoundTaxAdjustment(5M)
};

Lasse,我再次看了几个场景,我已经对此发表了评论,但我相信我的计算错误。在以不同的方式进行计算之后,我的数字与您的数字相匹配并且所有方案都通过了。例如,给定:

var adjustments = new Adjustment[]
{
    new NonCompoundTaxAdjustment(7M),
    new NonCompoundTaxAdjustment(3M),
    new CompoundTaxAdjustment(-5M)
};

我用计算器(100 * 1.1)/ 1.05 = 104.761904做这个,但后来我试了

100 * 1.1 = 110 110 * 0.05 = 5.5 110 - 5.5 = 104.5这与你的计算相符,所以我猜你这样处理它。

一个想法:

如果从100减去7%并按这样做:

100 - (100 * 0.07)= 93.现在好像是不正确的,因为要加回7%,即93 * 1.07,你得到100,你得到99.51。从100减去7%实际上应该是100 / 1.07 = 93.45当你拿93.45 * 1.07时,你会回到100

我被困在这里。

当前代码似乎只能正确处理添加百分比。例如,如果我添加+ 7%到200,我得到214是正确的并且回到200,代码执行214 / 1.07这也是正确的。问题是,如果我想从214中删除7%,代码正在执行.93 * 200 = 186,这是不正确的。从200中删除7%实际上是200 / 1.07 = 186.9158878504673。取这个值并乘以7%或186.9158878504673 * 1.07 = 200,但如果我拿186 * 1.07,我得到199.02而不是200。

2 个答案:

答案 0 :(得分:1)

好的,这就是我的所作所为。

我开始使用由两个数字组成的公式,一个因子和一个偏移量。

公式如下:

result = input * factor + offset

公式的起始因子为1,偏移量为0,所以基本上未经调整的公式如下所示:

result = input * 1 + 0
result = input * 1
result = input           <-- as expected

然后,对于每次调整,我按如下方式调整公式:

  • 平坦值:将平坦值添加到偏移量
  • 复合税:将因子和偏移量乘以1 + PERCENTAGE/100
  • 非复合税:将PERCENTAGE/100的值加到因子上。 (编辑:是1+,这是不正确的)

这意味着你的例子:

  • 7%非复合税
  • 3%复合税
  • 5%非复合税

结果如下:

result = input * factor + offset
result = input * 1      + 0
result = input * 1.07   + 0      <-- add 0.07 to factor
result = input * 1.1021 + 0      <-- multiply both factor and offset by 1.03
result = input * 1.1521 + 0      <-- add 0.05 to factor

要计算100的百分比,在添加税后,您可以通过公式提供它并获取:

result = 100 * 1.1521 + 0
result = 115.21

要计算115.21是多少,在添加税之前,您可以通过求解输入来反转公式:

 result                    = input * factor + offset
 result - offset           = input * factor
(result - offset) / factor = input
                     input = (result - offset) / factor

所以:

input = (result - 0) / 1.1521
input = result / 1.1521

然后你就回来了。

您可以在LINQPad中测试的代码如下:

void Main()
{
    var adjustments = new Adjustment[]
    {
        new CompoundTaxAdjustment(7M),
        new NonCompoundTaxAdjustment(3M),
        new CompoundTaxAdjustment(5M)
    };

    var original = 100M;

    var formula = Adjustment.GenerateFormula(adjustments);

    var result = formula.Forward(original).Dump(); // prints 115,5
    var newOriginal = formula.Backward(result).Dump(); // prints 100
}

public abstract class Adjustment
{
    public class Formula
    {
        public decimal Factor = 1.0M;
        public decimal Offset;

        public decimal Forward(decimal input)
        {
            return input * Factor + Offset;
        }

        public decimal Backward(decimal input)
        {
            return (input - Offset) / Factor;
        }
    }

    public static Formula GenerateFormula(IEnumerable<Adjustment> adjustments)
    {
        Formula formula = new Formula();
        foreach (var adjustment in adjustments)
            adjustment.Adjust(formula);
        return formula;
    }

    protected abstract void Adjust(Formula formula);
}

public class FlatValueAdjustment : Adjustment
{
    private decimal _Value;

    public FlatValueAdjustment(decimal value)
    {
        _Value = value;
    }

    protected override void Adjust(Formula formula)
    {
        formula.Offset += _Value;
    }
}

public abstract class TaxAdjustment : Adjustment
{
    protected TaxAdjustment(decimal percentage)
    {
        Percentage = percentage;
    }

    protected decimal Percentage
    {
        get;
        private set;
    }
}

public class CompoundTaxAdjustment : TaxAdjustment
{
    public CompoundTaxAdjustment(decimal percentage)
        : base(percentage)
    {
    }

    protected override void Adjust(Formula formula)
    {
        var myFactor = 1M + Percentage / 100M;
        formula.Offset *= myFactor;
        formula.Factor *= myFactor;
    }
}

public class NonCompoundTaxAdjustment : TaxAdjustment
{
    public NonCompoundTaxAdjustment(decimal percentage)
        : base(percentage)
    {
    }

    protected override void Adjust(Formula formula)
    {
        formula.Factor += (Percentage / 100M);
    }
}

我给出的例子看起来像这样,让我们​​先手动完成。

  • 1%复合,1%非复合,平坦值为1,1%复合,1%未复合,1%复合
  • 从100开始,加1%的复合税,得到101
  • 加入1%的非复合税,1%的100,得到102
  • 添加平面值1,得到103
  • 添加1%的compoundex税,获得104,03
  • 添加1%的非复合税,1%的100,得到105,03
  • 添加1%的复合税,得到106,0803

代码输入:

var adjustments = new Adjustment[]
{
    new CompoundTaxAdjustment(1M),
    new NonCompoundTaxAdjustment(1M),
    new FlatValueAdjustment(1M),
    new CompoundTaxAdjustment(1M),
    new NonCompoundTaxAdjustment(1M),
    new CompoundTaxAdjustment(1M)
};

输出:

106,0803000
100

答案 1 :(得分:0)

这就是我这样做的方式。它适用于大多数情况,特别是如果您将非复合百分比放在首位。如果有人有任何改进或通知任何错误,请告诉我:

void Main()
{
Adjustment a1 = new Adjustment {Amount = 12.0M, IsCompounded = false, Add = false, Percent = false};
Adjustment a2 = new Adjustment {Amount = 3.0M, IsCompounded = true, Add = true, Percent = true};
Adjustment a3 = new Adjustment {Amount = 5.0M, IsCompounded = true,  Add = true ,Percent = true};


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

decimal total = 103.55987055016181229773462783m;
decimal adjustedTotal = total;
decimal nonCompoundValues = 0.0m;
decimal compoundValues = 1.0m;
string prevType = "";

for(int i = 0; i <= adjustments.Count - 1; i++)
{

    if(adjustments[i].Percent)
    {
        if(adjustments[i].IsCompounded)
        {

            if(i == adjustments.Count - 1  && adjustments[i].IsCompounded)
            {
                if(adjustments[i].Add)
                {
                    nonCompoundValues += adjustments[i].Amount/100.0m;

                }
                else
                {
                    nonCompoundValues -= adjustments[i].Amount/100.0m;

                }
                break;
            }

            if(nonCompoundValues < 0  & prevType != "Compound") //Remove tax
            {

                adjustedTotal /= compoundValues + Math.Abs(nonCompoundValues);
                nonCompoundValues = 0.0m;
                compoundValues = 1.0m;

            }
            else if(nonCompoundValues > 0 & prevType != "Compound") //Add tax
            {

                adjustedTotal *= compoundValues + Math.Abs(nonCompoundValues);
                nonCompoundValues = 0.0m;
                compoundValues = 1.0m;
            }


            if(adjustments[i].Add)
            {

                if(prevType == "" || prevType == "Compound")
                {
                    adjustedTotal *= 1 + adjustments[i].Amount/100.0m; //add compound first
                    compoundValues = 1.0m;
                }
                else
                {
                    compoundValues *= 1 + adjustments[i].Amount/100.0m;
                }
            }
            else
            {

                if(prevType == "" || prevType == "Compound")
                {
                adjustedTotal /= 1 + adjustments[i].Amount/100.0m;

                compoundValues = 1.0m;
                }
                else
                {
                    compoundValues /= 1 + adjustments[i].Amount/100.0m;
                }
            }

            prevType = "Compound";

        }
        else // Non-Compound
        {

            if(adjustments[i].Add)
            {
                nonCompoundValues += adjustments[i].Amount/100.0m;

            }
            else
            {
                nonCompoundValues -= adjustments[i].Amount/100.0m;
            }

            prevType = "Non-compound";

        }

    }
    else //flat
    {
        if(nonCompoundValues < 0) //Remove tax
            {

                adjustedTotal /= compoundValues + Math.Abs(nonCompoundValues);
                nonCompoundValues = 0.0m;
                compoundValues = 1.0m;

            }
            else if(nonCompoundValues > 0) //Add tax
            {

                adjustedTotal *= compoundValues + Math.Abs(nonCompoundValues);
                nonCompoundValues = 0.0m;
                compoundValues = 1.0m;
            }

        if(adjustments[i].Add)
        {
            adjustedTotal += adjustments[i].Amount;
        }
        else
        {
            adjustedTotal -= adjustments[i].Amount;
        }

    }
}


if(nonCompoundValues < 0)
{

    adjustedTotal /= compoundValues + Math.Abs(nonCompoundValues);
}
else
{
    adjustedTotal *=compoundValues + Math.Abs(nonCompoundValues);
}
Console.WriteLine(adjustedTotal);

}


public class Adjustment
{
public bool Percent {get;set;}
public decimal Amount {get;set;}
public bool IsCompounded {get;set;}
public bool Add{get;set;}
public decimal AmountFraction
{
get {
    return Amount/100.0M;
}
}
public decimal CompoundedValue
{
    get{
        return 1 + AmountFraction;
    }
}
}