我正在嘗試通過執行階乘函式來計算歐拉數(e = 2.718281828459045235),然后使用while回圈呼叫它來計算常數。問題是我宣告了一個i變數以使回圈在i<50的情況下作業,如下所示,它給了我以下輸出:
歐拉數為:2.7182818284590455
但是,我希望程式輸出更多小數,但無論我如何增加回圈中的i<50條件,它總是給出相同數量的小數。
我嘗試將 while 回圈的條件更改為i<150,并將“long”變數修改為“ulong”變數,但沒有任何反應,它總是給出相同的輸出。知道如何改變嗎?
任何形式的幫助將不勝感激,謝謝!
我的代碼:
using System;
namespace eulerNumber
{
class eulerCalculator
{
public static double factorial(long n)
{
if (n == 0)
{
return 1;
}
else if (n == 1)
{
return 1;
}
else
{
return n * factorial(n - 1);
}
}
static void Main(string[] args)
{
double addition = 0, i = 0;
while(i<50)
{
addition = addition (1 / factorial((long)i));
i ;
}
Console.WriteLine("The number of euler is: " addition);
}
}
}
uj5u.com熱心網友回復:
一個相當簡單的改進是首先從最小的項開始執行加法,因此它們的大小相似,并且處理器可以在不損失太多精度的情況下執行加法。
注意:factorial(50)是50 * factorial(49),最后兩項是1/factorial(49) 1/factorial(50)。應用一些代數得到1/factorial(49) 1.0/50/factorial(49),即(1 1.0/50) / factorial(49)
假設您只計算分子,并跟蹤分母中出現的階乘而不計算它。現在你有兩個非常好的屬性:
- 您永遠不必計算溢位的數字(如階乘(i))和
- 無論更新方程中存在什么舍入誤差,都與最終答案無關,因為它是一個術語中的誤差,它會被進一步劃分并變得更小
這導致以下代碼:
double accumulator = 1.0;
for( int i = 50; i > 0; --i )
{
accumulator = 1.0 accumulator / i;
}
演示:https ://rextester.com/FEZB44588
使用 .NET 的 BigInteger 類的擴展允許我們擁有更多位數的精度
BigInteger scale = BigInteger.Pow(10, 60);
BigInteger accumulator = scale;
for( int i = 75; i > 0; --i )
{
accumulator = scale accumulator / i;
}
結果(插入小數點):
2.718281828459045235360287471352662497757247093699959574966967
來自維基百科的前 50 位小數:
2.71828182845904523536028747135266249775724709369995...
請注意,維基百科的措辭略有錯誤,這不是四舍五入到小數點后 50 位的值,這些是連續序列的前 50 位小數
uj5u.com熱心網友回復:
我很無聊,所以我將e=(1 1/x)^x方法編碼為簡單的 C (抱歉不是 C# 編碼器),沒有任何庫或直接在字串上計算的有趣的東西......
我還將演算法從二進制移植到十進制基數,代碼如下:
//---------------------------------------------------------------------------
// string numbers are in format "?.??????????????"
// where n is number of digits after decimal separator
void str_addmul(char *xy,char *x,char *y,int k,int n) // xy = x y*k, k = 0..9
{
int i,a,cy;
for (cy=0,i=n 1;i>=0;i--)
{
if (i==1) i--; // skip decimal separator
a=(x[i]-'0') ((y[i]-'0')*k) cy;
cy = a/10;
xy[i]=(a%10) '0';
}
xy[1]='.';
xy[n 2]=0;
}
//---------------------------------------------------------------------------
// string numbers are in format "?.??????????????"
// where n is number of digits after decimal separator
void str_mul(char *xy,char *_x,char *_y,int n) // xy = x*y
{
int i,j;
// preserve original _x,_y and use temp x,y instead
char *x=new char[n 3]; for (i=0;i<n 3;i ) x[i]=_x[i];
char *y=new char[n 3]; for (i=0;i<n 3;i ) y[i]=_y[i];
// xy = 0.000...000
i=0;
xy[i]='0'; i ;
xy[i]='.'; i ;
for (;i<n 2;i ) xy[i]='0';
xy[i]=0;
// xy = x*y
for (i=0;i<n 2;i )
{
if (i==1) i ; // skip decimal separator
str_addmul(xy,xy,x,y[i]-'0',n);
// x/=10
for (j=n 1;j>2;j--) x[j]=x[j-1];
x[2]=x[0]; x[0]='0';
}
delete[] x;
delete[] y;
}
//---------------------------------------------------------------------------
char* compute_e(int n) // e = (1 1/x)^x where x is big power of 10
{
int i,x10,m=n n 4;
char* c=new char[m 3]; // ~double precision
char* a=new char[m 3]; // ~double precision
char* e=new char[n 3]; // target precision
// x = 10^m
// c = 1 1/x = 1.000...0001;
i=0;
c[i]='1'; i ;
c[i]='.'; i ;
for (;i<m 1;i ) c[i]='0';
c[i]='1'; i ;
c[i]=0;
// c = c^x
for (x10=0;x10<m;x10 )
{
str_mul(a,c,c,m); // c^2
str_mul(c,a,a,m); // c^4
str_mul(c,c,c,m); // c^8
str_mul(c,c,a,m); // c^10
}
// e = c
for (i=0;i<n 2;i ) e[i]=c[i]; e[i]=0;
delete[] a;
delete[] c;
return e;
}
//---------------------------------------------------------------------------
用法:
char *e=compute_e(100); // 100 is number of digits after decimal point
cout << e; // just output the string somewhere
delete[] e; // release memory after
與參考的結果compute_e(100):
e(100) = 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
e(ref) = 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
代碼很慢,因為它是在字串和 base10 中而不是在 base2 中的整數陣列上計算的,并且只使用了幼稚的數學運算實作......但是在我的古老 PC 上仍然完成了 100 位335 ms和 200 位2612.525 ms,并且應該更快比您的迭代精度相同...
要使用 base10 演算法,等式是:
x = 10^digits
e = (1 1/x) ^ x
所以當你用十進制寫x這個詞(1 1/x)時,你會得到:
x = 1000000000000 ... 000000
c = (1 1/x) = 1.0000000000000 ... 000001
現在我只是通過平方成冪來修改冪10ing?而不是c = c*c我迭代的地方c = c*c*c*c*c*c*c*c*c*c,就是這樣......
由于這些東西是在以 10 為基數的字串上計算的,因此無需在數字表示和文本之間進行轉換以進行列印...
最后,為了獲得n十進制數字的精度,我們必須使用m = 2*n 4數字精度進行計算,并將最終結果切割成n數字......
所以只需將這些東西移植到 C# 你可以使用字串而不是char*這樣你就可以擺脫new[]/delete[]C# 中的其余部分應該是相同的......
有點好奇,所以我稍微測量了一下:
[ 0.640 ms] e( 10) = 2.7182818284
[ 3.756 ms] e( 20) = 2.71828182845904523536
[ 11.172 ms] e( 30) = 2.718281828459045235360287471352
[ 25.234 ms] e( 40) = 2.7182818284590452353602874713526624977572
[ 46.053 ms] e( 50) = 2.71828182845904523536028747135266249775724709369995
[ 77.368 ms] e( 60) = 2.718281828459045235360287471352662497757247093699959574966967
[ 121.756 ms] e( 70) = 2.7182818284590452353602874713526624977572470936999595749669676277240766
[ 178.508 ms] e( 80) = 2.71828182845904523536028747135266249775724709369995957496696762772407663035354759
[ 251.713 ms] e( 90) = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178
[ 347.418 ms] e(100) = 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
e(ref) = 2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
并使用它揭示了~O(n^2.8)復雜性
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/480082.html
下一篇:React-計算圓中的點位置
