纠结于从价值中移除/添加多个税

本文关键字:添加 | 更新日期: 2023-09-27 17:53:07

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

调整可以是复合或非复合的百分比。它也可以是一个固定的金额。它也可以添加或删除到初始值。我只需要把税后值和税后值反向的部分写出来。我写了一些可以用来生成测试数据的东西,我还写了一些可以从测试数据生成的税后值逆转这些调整的东西。我认为我在应用调整和撤消它们方面做得太过分了。调整是按顺序应用的,所以一个包含(+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%的非复利税,那么您首先将100的3%加起来得到103,然后从103中减去100的4%得到99。

如果4%是复利的,你将从103中扣除4%,而不是100,所以它将是:

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万。

基本上,当我将复利/非复利与加减数量混合时,它开始不能产生正确的结果。

不通过的调整:

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 = 110110 * 0.05 = 5.5110 - 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的价值因子。(edit: was 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<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%复合
  • 从100开始,加上1%的复利税,得到101
  • 加上1%的非复利税,100的1%,得到102
  • 添加1的平坦值,得到103
  • 增加1%的复合税,得到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<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;
    }
}
}