欧拉数与任务 [英] Euler number with tasks

查看:54
本文介绍了欧拉数与任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用此公式= ∑((3k)^ 2+ 1)/(3k)!,k = 0,...,∞,但是到目前为止我没有得到正确的结果,而且有一次问题是当我使用相当大的数字时,析因函数的十进制数超出了范围,这就是我到目前为止已经完成

 静态void Main(string [] args){Console.WriteLine(Program.Calculate(5,1));}公共静态十进制Calculate(int x,字节taskNumber){var task = new List< Task< decimal>>();对于(int i = 0; i< x; i + =(x/taskNumber)){国际步=我;task.Add(Task.Run(()=>{int right =(step + x/taskNumber)>X ?x:(step + x/taskNumber);返回ChunkE(step + 1,right);}));}Task.WaitAll(tasks.ToArray());返回任务.Select(t => t.Result).Aggregate((((i,next)=> i + next));} 

然后我有简单的阶乘和欧拉函数

 公共静态十进制ChunkFactorial(向左整数,向右整数){//Console.WriteLine("ChunkFactorial Thread ID:"+ Thread.CurrentThread.ManagedThreadId);如果(左==右){返回左== 0吗?1:左;}别的{返回右* ChunkFactorial(left,right-1);}}公共静态十进制ChunkE(int左,int右){如果(左==右){返回左== 0吗?1:左;}别的{return((3 *右)*(3 *右)+ 1)/ChunkFactorial(左,右)+ ChunkE(左,右-1);}} 

我要实现的是使用不同数量的任务计算直到 x 精度的欧拉数.

如果我增加 x 十进制数,那么我通过这个电话得到的是41.01666..7.我该如何解决使用BigInteger尝试解决的问题,但后来变得一团糟,结果的精度下降了.

另外,当我用1个任务启动程序时,我得到一个结果,当我用4(或1个不同值)启动程序时,我得到了不同的结果,我不知道自己缺少什么..

解决方案

由于已经回答了这个问题的要点,所以我只添加了一些内容:

您可以对代码进行很少的升级,例如每次计算阶乘和除数时都可以用 2 5 进行除数,以降低所需的位.如果操作正确,这也将大大提高速度.

但是最后,您的公式仍需要花费永远的时间才能收敛到 e !更不用说因阶乘导致的溢出.我正在使用更适合计算机的东西(虽然很早以前就不确定公式的来源)...

  e =(1 + 1/x)^ x 

其中 x->+inf 这在使用数字的二进制表示时有很多优点.我通过对 x 使用 2 的能力来完善过程,从而大大简化了工作...我的计算代码(基于我的 arbnum 类)就是这样:

  arbnum c,x;整数位= 512;//min(int_bits,fract_bits)/2 ...这只是定点代码中余量很大的地方,位宽很重要//e =(1 + 1/x)^ x ... x->+ inf锥体();c>> =位;c ++;//c = 1.000 ... 0001b =(1 + 1/x)= 2 ^位+ 1//x.one();x<< =位;//x = 1000 ... 000.0b = x = 1/(c-1)= 2 ^ +位for(; bit; bit--)//c = c ^ x = c ^(2 ^ bits)= e{c * = c;c._normalize(2048);//这只是将结果截断为特定数量的小数位数,只是为了加快计算速度,而应该只截断最后一个零!} 

如您所见,我从头开始计算目标精度( bits ),然后将结果截断(减小为小数部分的可管理位宽).如果你有定点算术,那么你根本不需要这样做(这只是我快速尝试将它从我古老的定点代码移植到我的新 arbnum 类).

因此,将位常量设置为所需的值,并设置截断大小.两者都应基于您的目标精度.正如您所看到的,这不是迭代过程...循环中唯一的东西是 power.对其进行了一些优化,以了解您需要了解要计算的内容:

 (1.000 ... 0001b)^(1<<位) 

所以我只是将 c 平方,直到命中 x 中的第一个有符号位.请注意,每次平方运算都会使所需的小数位宽度加倍...这就是被截断的原因(它降低了准确度,蝙蝠提高了性能,更多)

如您所见,这种方法非常好,因为它不需要任何除法...仅需位运算和乘法.

在这里比较:

  [e]参考2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274我的e 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427400000200方法0:2.7182818280709941626033162692782994994997597533824790948079298224728031965377356362865659816488677135209 

引用 e 的前100位数字. my e 是此代码的结果,而 method 0 是您的方程式经过200次迭代后以任意精度(最后零被截断)和%2,%5的结果.优化以加快速度.

我的方法只花了几毫秒,而您的〜20 秒就达到了这一点...

I want to calculate Euler number with multiple threads using this formula =∑((3k) ^ 2 + 1)/(3k)! , k =0,... ,∞ , but I am not getting the right results so far and once of the problems is that when I use fairly big number I am going out of range for decimal for factorial function here is what I've done so far

static void Main(string[] args)
{
   Console.WriteLine(Program.Calculate(5, 1));
}
public static decimal Calculate(int x, byte taskNumber)
{
   var tasks = new List<Task<decimal>>();

   for (int i = 0; i < x; i += (x / taskNumber))
   {
        int step = i;
        tasks.Add(Task.Run(() =>
        {
            int right = (step + x / taskNumber) > x ? x : (step + x / taskNumber);
            return ChunkE(step + 1, right);
        }));
    }

    Task.WaitAll(tasks.ToArray());

    return tasks.Select(t => t.Result).Aggregate(((i, next) => i + next));
    }

then I have simple factorial and euler functions

public static decimal ChunkFactorial(int left, int right)
{
    //Console.WriteLine("ChunkFactorial Thread ID :" + Thread.CurrentThread.ManagedThreadId);
    if (left == right)
    {
        return left == 0 ? 1 : left;
    }
    else
    {
        return right * ChunkFactorial(left, right - 1);
    }
}

public static decimal ChunkE(int left, int right)
{
    if(left == right)
    {
        return left == 0 ? 1 : left;
    }
    else
    {
        return ((3 * right) * (3 * right) + 1) / ChunkFactorial(left, right) + ChunkE(left, right - 1);
    }
}

What I want to achieve is calculating Euler number up until x precision using different amount of tasks.

What I am getting with this call is 41.01666..7 if I increase x decimal will eventually overflow. How can I fix this problem I tried using BigInteger but then it begin to be mess and I loose precision of the result.. Any ideas?

Also when I start the program with 1 task I get one result and when I start program with 4(or different of 1) I get different result I don't know what I am missing..

解决方案

As the main point of this question was already answered I just add some stuff:

You can do few upgrades to your code like while computing factorial each time you can divide both divident and divider by 2 or 5 do it to lower the bits needed. This will also boost the speed a lot if done right.

But in the end Your formula will still take forever to converge to e! Not to mention the overflows due to factorial. I am using something better suited for computers (not sure where the formula comes from though it was ages ago)...

e = (1+1/x)^x

where x -> +inf This has many advantages when using binary representations of numbers. I refined the process by using powers of 2 for x which simplifies things a lot... My computation code (based on my arbnum class) is as this:

    arbnum c,x;
    int bit=512;        // min(int_bits,fract_bits)/2 ... this is just remnant from fixed point code where bitwidth matters
    // e=(1+1/x)^x  ... x -> +inf
    c.one(); c>>=bit; c++;  // c = 1.000...0001b = (1+1/x)          = 2^-bits + 1
//  x.one(); x<<=bit;       // x = 1000...000.0b =    x   = 1/(c-1) = 2^+bits
        for (;bit;bit--)        // c = c^x = c^(2^bits) = e
            {
            c*=c;
            c._normalize(2048); // this just cut off the result to specific number of fractional bits only to speed up the computation instead you should cut of only last zeros !!!
            }

As you can see I am computing target precision from the start (bits) and truncating the result (to manageable bit width for fractional part). If you got fixed point arithmetics then you do not need to do this at all (this was just my fast attempt to port it from my ancient fixed point code to my new arbnum class).

So set the bits constant to what you want and also the truncating size. Both should be based on your target precision. As you can see this is not iterative process... The only thing that is in loop is the power. It is optimized a bit to understand it you need to realize what are you computing:

(1.000...0001b) ^ (1<<bits)

so I just square the c until first signed bit in x is hit. Beware each squaring doubles the needed fractional bit width ... that is the reason for truncation (it lowers accuracy bat boosts performance much much more)

As you can see this approach is quite nice as it does not need any division ... only bit operations and multiplication.

Here comparison:

[e]
reference          2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
my e               2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
00000200 method 0: 2.7182818280709941626033162692782994930797533824790948079298224728031965377356362865659816488677135209

The reference is first 100 digits of e. The my e is result from this code and method 0 is result from your equation after 200 iterations in arbitrary precision with last zero truncating and the %2,%5 optimization to speed it up.

Mine approach took just few milliseconds and yours ~20 seconds to get to that point...

这篇关于欧拉数与任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆