Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将十进制数提高到十进制数的幂次方?_C#_Bigdecimal_Decimal - Fatal编程技术网

C# 将十进制数提高到十进制数的幂次方?

C# 将十进制数提高到十进制数的幂次方?,c#,bigdecimal,decimal,C#,Bigdecimal,Decimal,net framework在Math类中提供了一种为double供电的方法。但根据精度要求,我需要将一个十进制数提高到一个十进制幂[Pow(十进制a,十进制b)]。框架是否具有这样的功能?有人知道具有这种功能的库吗?您确定要这样做吗?一个decimal乘法大约比double慢40倍,所以我认为decimalMath.Pow()实际上是不可用的 但是,如果您只期望整数幂,我建议您使用基于整数的幂算法,这在这里已经讨论过了 我认为这在很大程度上取决于你计划接入的电话号码。如果‘a’和‘b’不是‘好’

net framework在Math类中提供了一种为double供电的方法。但根据精度要求,我需要将一个十进制数提高到一个十进制幂[Pow(十进制a,十进制b)]。框架是否具有这样的功能?有人知道具有这种功能的库吗?

您确定要这样做吗?一个
decimal
乘法大约比
double
慢40倍,所以我认为decimal
Math.Pow()
实际上是不可用的


但是,如果您只期望整数幂,我建议您使用基于整数的幂算法,这在这里已经讨论过了

我认为这在很大程度上取决于你计划接入的电话号码。如果‘a’和‘b’不是‘好’的数字,那么你可能会得到一个无法存储的非终止值,如果C#BigDecimal的行为与Java BigDecimal完全一样,那么在这种情况下它可能会抛出一个异常。

为了解决我的问题,我找到了一些,并且实现了它们来解决方程X^n=e^(n*lnx)


Pow()和Factorial()函数很简单,因为幂始终是int(在de幂级数中)。

对于正整数指数和十进制基数,这应该是最快的:

// From http://www.daimi.au.dk/~ivan/FastExpproject.pdf
// Left to Right Binary Exponentiation
public static decimal Pow(decimal x, uint y){
    decimal A = 1m;
    BitArray e = new BitArray(BitConverter.GetBytes(y));
    int t = e.Count;

    for (int i = t-1; i >= 0; --i) {
        A *= A;
        if (e[i] == true) {
            A *= x;
        }
    }
    return A;
}
这是一个C#程序,它可以手动实现Math.Pow(),比基于.NET的double实现更精确。 剪切并粘贴到linqpad以立即运行,或将.Dump()更改为Console.WriteLines

我已经包括了对结果的测试。测试如下:

  • 目标=0.4%pa,每日复利为10000
  • 答案=应为10 040
  • How=十进制b=10000;对于(int i=0;ix=1-a=1-1.004=-.004 y=b*ln(a) 经验(y)=1+y+y^2/2+x^3/3!+y^4/4!+y^5/5!+。。。 n!=1*2*…*n */ /* // //示例:R10000上的4%pa,每日配制 // 人工计算费率:1.0000109371043837652682334292 Excel比率:1.000010937104383712500000M=(1.004)^(1/365) 数学功率率:1.00001093710438 手动-R10000上的0.4%pa:10040.000000000000000131 R10000上的Excel-0.4%pa:10039.99999998066627646709094 R10000上的数学功率-0.4%pa:10039.99999986201948942509648 */ 静态uint _LOOPS=10;//Max=22,在本示例场景中,10之后的精度没有提高 // 8: 1.0000109371043837652682333497 // 9: 1.0000109371043837652682334295 // 10: 1.0000109371043837652682334292 // ... // 21: 1.0000109371043837652682334292 // 22: 1.0000109371043837652682334292 // http://www.daimi.au.dk/~ivan/fastexproject.pdf //从左到右的二进制求幂 公共静态十进制功率(十进制x,uint y) { 如果(y==1) 返回x; 十进制A=1m; BitArray e=新的BitArray(BitConverter.GetBytes(y)); int t=e.计数; 对于(int i=t-1;i>=0;--i){ A*=A; 如果(e[i]==真){ A*=x; } } 返回A; } // http://stackoverflow.com/questions/429165/raising-a-decimal-to-a-power-of-decimal //自然对数级数 公共静态十进制项次(十进制a) { /* ln(a)=log(1-x)=-x-x^2/2-x^3/3-…(其中| x |<1) x:a=1-x=>x=1-a=1-1.004=-.004 */ 十进制x=1-a; 如果(数学绝对值(x)>=1) 抛出新异常(“必须是00) { 结果-=Pow(x,迭代)/迭代; 迭代--; } 返回结果; } 公共静态ulong[]事实=新ulong[]{ 1L, 1L*2, 1L*2*3, 1L*2*3*4, 1L*2*3*4*5, 1L*2*3*4*5*6, 1L*2*3*4*5*6*7, 1L*2*3*4*5*6*7*8, 1L*2*3*4*5*6*7*8*9, 1L*2*3*4*5*6*7*8*9*10, 1L*2*3*4*5*6*7*8*9*10*11, 1L*2*3*4*5*6*7*8*9*10*11*12, 1L*2*3*4*5*6*7*8*9*10*11*12*13, 1L*2*3*4*5*6*7*8*9*10*11*12*13*14, 1L*2*3*4*5*6*7*8*9*10*11*12*13*14*15, 1L*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16, 1L*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17, 1L*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18, 1L*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19, 1L*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20, 14197454024290336768L,//1L*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20*21,//注意:编译时溢出 17196083355034583040L,//1L*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20*21*22//注意:编译时溢出 }; // http://stackoverflow.com/questions/429165/raising-a-decimal-to-a-power-of-decimal //幂级数 公共静态十进制exp(十进制y) { /* 经验(y)=1+y+y^2/2+x^3/3!+y^4/4!+y^5/5!+。。。 */ uint迭代=_循环; 小数结果=1; 而(迭代>0) { //uint fatorial=阶乘(迭代); ulong fatorial=事实[迭代-1]; 结果+=(Pow(y,迭代)/结局); 迭代--; } 返回结果; } void Main() { 十进制a=1.004M; 十进制b=1/365M; 十进制_ln=ln(a); 十进制y=b*_ln; 小数结果=exp(y); 结果。转储(“手动速率”); 十进制excel=1.000010937104383712500000M;//=(1.004)^(1/365) excel.Dump(“excel费率”); 十进制m=(十进制)数学功率((双)a,(双)b); m、 转储(“数学功率率”); //(结果-excel)。转储(“差异:手动-excel”); //Dump(“Diff:Math.Pow-excel”); var f=新日期时间(2013,1,1); var t=新日期时间(2014,1,1); 测试(f,t,10000,结果,“手动
    // From http://www.daimi.au.dk/~ivan/FastExpproject.pdf
    // Left to Right Binary Exponentiation
    public static decimal Pow(decimal x, uint y){
        decimal A = 1m;
        BitArray e = new BitArray(BitConverter.GetBytes(y));
        int t = e.Count;
    
        for (int i = t-1; i >= 0; --i) {
            A *= A;
            if (e[i] == true) {
                A *= x;
            }
        }
        return A;
    }
    
    Manually calculated rate:   1.0000109371043837652682334292
    Excel rate:                 1.000010937104383712500000M [see formula =(1.004)^(1/365)]
    Math.Pow rate:              1.00001093710438
    
    Manual - .4%pa on R10,000:  10040.000000000000000000000131 
    Excel - .4%pa on R10,000:   10039.999999999806627646709094 
    Math.Pow - .4%pa on R10,000:10039.999999986201948942509648
    
    /*
    a^b = exp(b * ln(a))
        ln(a) = log(1-x) = - x - x^2/2 - x^3/3 - ...   (where |x| < 1)
            x: a = 1-x    =>   x = 1-a = 1 - 1.004 = -.004
        y = b * ln(a)
        exp(y) = 1 + y + y^2/2 + x^3/3! + y^4/4! + y^5/5! + ...
            n! = 1 * 2 * ... * n        
    */
    
    /*
    //
    // Example: .4%pa on R10,000 with daily compounding
    //
    
    Manually calculated rate:   1.0000109371043837652682334292
    Excel rate:                 1.000010937104383712500000M =(1.004)^(1/365)
    Math.Pow rate:              1.00001093710438
    
    Manual - .4%pa on R10,000:  10040.000000000000000000000131 
    Excel - .4%pa on R10,000:   10039.999999999806627646709094 
    Math.Pow - .4%pa on R10,000:10039.999999986201948942509648 
    
    */
    
    static uint _LOOPS = 10;    // Max = 22, no improvement in accuracy after 10 in this example scenario
    //  8: 1.0000109371043837652682333497
    //  9: 1.0000109371043837652682334295
    // 10: 1.0000109371043837652682334292
    // ...
    // 21: 1.0000109371043837652682334292
    // 22: 1.0000109371043837652682334292
    
    // http://www.daimi.au.dk/~ivan/FastExpproject.pdf
    // Left to Right Binary Exponentiation
    public static decimal Pow(decimal x, uint y)
    {
        if (y == 1)
            return x;
    
        decimal A = 1m;
        BitArray e = new BitArray(BitConverter.GetBytes(y));
        int t = e.Count;
    
        for (int i = t-1; i >= 0; --i) {
            A *= A;
            if (e[i] == true) {
                A *= x;
            }
        }
        return A;
    }
    
    // http://stackoverflow.com/questions/429165/raising-a-decimal-to-a-power-of-decimal
    // natural logarithm series
    public static decimal ln(decimal a)
    {
        /*
        ln(a) = log(1-x) = - x - x^2/2 - x^3/3 - ...   (where |x| < 1)
            x: a = 1-x    =>   x = 1-a = 1 - 1.004 = -.004
        */
        decimal x = 1 - a;
        if (Math.Abs(x) >= 1)
            throw new Exception("must be 0 < a < 2");
    
        decimal result = 0;
        uint iteration = _LOOPS;
        while (iteration > 0)
        {
            result -= Pow(x, iteration) / iteration;
            iteration--;
        }
        return result;
    }
    
    public static ulong[] Fact = new ulong[] {
        1L,
        1L * 2,
        1L * 2 * 3,
        1L * 2 * 3 * 4,
        1L * 2 * 3 * 4 * 5,
        1L * 2 * 3 * 4 * 5 * 6,
        1L * 2 * 3 * 4 * 5 * 6 * 7,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19,
        1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19 * 20,
        14197454024290336768L, //1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19 * 20 * 21,        // NOTE: Overflow during compilation
        17196083355034583040L, //1L * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19 * 20 * 21 * 22    // NOTE: Overflow during compilation
    };
    
    // http://stackoverflow.com/questions/429165/raising-a-decimal-to-a-power-of-decimal
    // power series
    public static decimal exp(decimal y)
    {
        /*
        exp(y) = 1 + y + y^2/2 + x^3/3! + y^4/4! + y^5/5! + ...
        */
    
        uint iteration = _LOOPS;
        decimal result = 1; 
        while (iteration > 0)
        {
            //uint fatorial = Factorial(iteration);
            ulong fatorial = Fact[iteration-1];
            result += (Pow(y, iteration) / fatorial);
            iteration--;
        }
        return result;
    }
    
    void Main()
    {   
        decimal a = 1.004M;
        decimal b = 1/365M;
    
        decimal _ln = ln(a);
        decimal y = b * _ln;
        decimal result = exp(y);
        result.Dump("Manual rate");
    
        decimal excel = 1.000010937104383712500000M;    // =(1.004)^(1/365)
        excel.Dump("Excel rate");
    
    
        decimal m = (decimal)Math.Pow((double)a,(double)b);
        m.Dump("Math.Pow rate");
    
        //(result - excel).Dump("Diff: Manual - Excel");
        //(m - excel).Dump("Diff: Math.Pow - Excel");
    
        var f = new DateTime(2013,1,1);
        var t = new DateTime(2014,1,1);
        Test(f, t, 10000, result, "Manual - .4%pa on R10,000");
        Test(f, t, 10000, excel, "Excel - .4%pa on R10,000");
        Test(f, t, 10000, m, "Math.Pow - .4%pa on R10,000");
    }
    
    decimal Test(DateTime f, DateTime t, decimal balance, decimal rate, string whichRate)
    {
        int numInterveningDays = (t.Date - f.Date).Days;
        var value = balance;
        for (int i = 0; i < numInterveningDays; ++i)
        {
            value *= rate;
        }
        value.Dump(whichRate);
        return value - balance;
    }
    
    /*
    
    // Other workings:
    
    //
    // Determine maximum Factorial for use in ln(a)
    //
    
    ulong max    =  9,223,372,036,854,775,807 * 2   // see http://msdn.microsoft.com/en-us/library/ctetwysk.aspx
    Factorial 21 = 14,197,454,024,290,336,768
    Factorial 22 = 17,196,083,355,034,583,040
    Factorial 23 = 8,128,291,617,894,825,984 (Overflow)
    
    public static uint Factorial_uint(uint i)
    {
        // n! = 1 * 2 * ... * n
        uint n = i;
        while (--i > 1)
        {
            n *= i;
        }
        return n;
    }
    
    public static ulong Factorial_ulong(uint i)
    {
        // n! = 1 * 2 * ... * n
        ulong n = i;
        while (--i > 1)
        {
            n *= i;
        }
        return n;
    }
    
    void Main()
    {
        // Check max ulong Factorial
        ulong prev = 0;
        for (uint i = 1; i < 24; ++i)
        {
            ulong cur = Factorial_ulong(i);
            cur.Dump(i.ToString());
            if (cur < prev)
            {
                throw new Exception("Overflow");
            }
            prev = cur;
        }
    }
    */