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

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

调整可以是复合或非复合的百分比。 它也可以是一笔不变的金额。 它也可以添加或删除到初始值。 我只需要编写从税后价值中反转税收的部分。 我写了一些我可以用来生成测试数据的东西,我写了一些其他的东西,可以从测试数据生成的税后价值中反转这些调整。 我认为我过度工程应用调整并取消应用。 调整是应用顺序,所以包含(+ 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 adjustments = new List(); 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 adjustments = new List(); 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的百分之四得到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。

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

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

公式如下:

 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 

你会收回你的100。

您可以在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 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%的非复合税,100%的1%,获得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 

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

 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 adjustments = new List(); 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; } } }