我必须从值中删除/添加多个税或调整以返回到应用它的原始值。我将定义调整的内容:
调整可以是复合或非复合的百分比。它也可以是一笔不变的金额。它也可以添加或删除到初始值。我只需要编写从税后价值中反转税收的部分。我写了一些我可以用来生成测试数据的东西,我写了一些其他的东西,可以从测试数据生成的税后价值中反转这些调整。我认为我过度工程应用调整并取消应用。调整是应用顺序,所以包含(+ 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。
答案 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+,这是不正确的)这意味着你的例子:
结果如下:
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);
}
}
我给出的例子看起来像这样,让我们先手动完成。
代码输入:
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;
}
}
}