65.9K
CodeProject 正在变化。 阅读更多。
Home

用 C# 完成的 BigNumber 类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (26投票s)

2009 年 8 月 31 日

CPOL

2分钟阅读

viewsIcon

68154

downloadIcon

1132

一个简单的 C# 库,用于进行任何所需精度的数学计算

引言

我想要编写一个简单的 C# 库,允许进行任意精度级别的数学计算。

背景

在过去的几个月里,我一直在研究数学库,并开始实现我自己的高精度数学库。我偶然发现了 MAPM 库 (http://www.tc.umn.edu/~ringx004/mapm-main.html),并决定为 .NET 创建一个类似的东西。这个库是我工作的成果。基本上,它是 MAPM 库在 .NET 上的重写。

我的目标是在我之前在 CodeProject 上发布的一个 Mandelbrot 分形渲染器 这里 中使用这个库。理论上,这应该提供无限地缩放到分形(以牺牲速度为代价)。我们很快就会看到会发生什么 ;-)

Using the Code

大数类的头部看起来像这样

public partial class BigNumber
{
        sbyte signum=0;
        int exponent=0;
        byte[] mantissa= {0};
        int dataLength=1; 
        
        ...
}

大数以 S * A * 10 ^ B 的形式表示,其中

  • S ... 是符号
  • A ... 是尾数
  • B ... 是指数

尾数表示为打包字节的数组。
每个字节的半字节代表数字的 2 位。
尾数可以具有任意长度。它限制为 1 < |a| < 10

打开项目,编译并运行。包含的测试程序将调用库的函数 DoTest()

查看 DoTest() 函数,了解如何使用这个库。您将找到如何

  • 将值赋给 BigNumber
  • 使用重载的运算符 +、-、* 和 / 进行基本的数学运算
  • 使用像四舍五入、sqrt、pow、log10、log2 等数学函数
  • 使用此库计算 1000!
  • 计算 PI 到所需的位数
public static void DoTest()
{
    BigNumber A = 0, B = 0, C = 0;
    BigNumber PI= new BigNumber();

    // assignment by string
    A = "12345";
    Console.WriteLine("assigned value was: " + A.ToFullString() + 
                      "(" + A.ToString() + ")");

    // assignment by double
    A = 123.45;
    Console.WriteLine("assigned value was: " + A.ToFullString() + 
                      "(" + A.ToString() + ")");

    // assignment by string in exponential form x = a*10^y. 10E3 = 10*10^^3 = 10000
    A = "10E3";     // 10E3 = 10*10^3 = 10000
    B = "1E4";      // 1E4  =  1*10^4 = 10000
    C = 10000;
    Console.WriteLine("assigned value was: " + A.ToFullString() + 
                      "(" + A.ToString()+")");
    Console.WriteLine("10000 = " + A.ToFullString() + " = " + 
                      B.ToFullString() + " = " + C.ToFullString());
    
    A = 1; B = 2; C = 0;
    C = A + B;
    Console.WriteLine("the result of " + A.ToFullString() + "+" + 
                      B.ToFullString() + "=" + C.ToFullString());
    // addition of BigNumber + double
    C = A + 3.2;
    // addition of double + BigNumber
    C = 3.1 + B;             
    A = "5.141592"; B = "2.91827";
    C = A - B;
    Console.WriteLine("the result of " + A.ToFullString() + 
                      "-" + B.ToFullString() + "=" + C.ToFullString());

    C = A * B;
    Console.WriteLine("the result of " + A.ToFullString() + 
                      "*" + B.ToFullString() + "=" + C.ToFullString());
    A = 5.0; B = 3.0;
    C = A * B;
    Console.WriteLine("the result of " + A.ToFullString() + 
                      "*" + B.ToFullString() + "=" + C.ToFullString());

    A = 4; B = 0.5;
    C = A.Pow(B);
    Console.WriteLine("the result of " + A.ToFullString() + 
                      " pow " + B.ToFullString() + "=" + C.ToFullString());

    A = 0.5; B = "5E-1";  
    C = A.Pow(B,16);
    Console.WriteLine("the result of " + A.ToFullString() + 
                      " pow " + B.ToFullString() + "=" + C.ToFullString());

    A = "1e3"; // "10E2"; //   "1E3 = 1000";
    C = A.Log10();
    Console.WriteLine("the result of " + A.ToFullString() + 
                      " Log10 =" + C.ToFullString());
   
    A = "10E3"; B = "1E4"; C=10000 ;

    A = BigNumber.BN_E;
    C = A.Log();
    Console.WriteLine("the result of " + A.ToString() + 
                      " Log =" + C.ToFullString());

    A = 3.0;
    C = A.Rez();
    Console.WriteLine("the result of " + A.ToString() + 
                      " Rez =" + C.ToFullString());

    int NumPlaces = 4;
    A = 1.53456;
    C = A.Round(NumPlaces);
    Console.WriteLine("the result of " + A.ToString() + 
                      " Round(" + NumPlaces + ") =" + 
                      C.ToFullString());

    NumPlaces = 2;
    C = A.Round(NumPlaces);
    Console.WriteLine("the result of " + A.ToString() + 
                      " Round(" + NumPlaces + ") =" + 
                      C.ToFullString());

    NumPlaces = 0;
    C = A.Round(NumPlaces);
    Console.WriteLine("the result of " + A.ToString() + 
                      " Round(" + NumPlaces + ") =" + 
                      C.ToFullString());

    NumPlaces = 16;
    A = 2.0;
    C = A.Sqrt(NumPlaces);
    Console.WriteLine("the result of " + A.ToString() + 
                      " Sqrt(" + NumPlaces + ") =" + 
                      C.ToFullString());

    A = 1.0; B = 0;
    try
    {
        C = A / B;
    }
    catch (BigNumberException ex)
    {
        Console.WriteLine("Exception in operation: " + ex.Message);
    }

    A = 1.0;
    for (int i = 1; i <= 1000; i++)
    {
        A = A * i;
    }
             
    Console.WriteLine("the result of 1000!=" + A.ToFullString());
    A = A.Round(numDefaultPlaces);
    Console.WriteLine("the result of 1000!=" + A.ToString());

    DateTime before = DateTime.Now;

    NumPlaces = 5000;
    CalculatePiAGM(PI, NumPlaces);

    TimeSpan ts = DateTime.Now - before;
    Console.WriteLine("time for "+NumPlaces+" digits of PI: " + 
                      ts.TotalMilliseconds + "[ms]");
    Console.WriteLine(PI.ToFullString());

    Console.WriteLine("Press 'x' key to quit test");
    while (true)
    {
        ConsoleKeyInfo i = Console.ReadKey();
        if (i.KeyChar == 'x') break;
    }
}

历史

  • 31.08.2009
    • 首次发布
  • 03.09.2009 
    • 实现了从二进制和十六进制字符串设置值
    • 修复了加法函数中的一个错误
© . All rights reserved.