Нужен тип данных для хранения более 1 миллиона цифр в C#

Я рассчитываю PI на С#, и пока он идеален, за исключением того, что мои типы данных ограничивают меня. Если я использую двойной, я получаю результаты, как показано ниже.

k=0, дельта= 3,14176587301587, pi=3,14176587301587

k=1, дельта=-0,000173301147482709, pi=3,14159257186839

k=2, дельта= 8,17736604635702E-08, pi=3,14159265364205

k=3, дельта=-5,22954018637708E-11, pi=3,14159265358975

k=4, дельта= 3,78997628626364E-14, pi=3,14159265358979

k=5, дельта=-2,94045250629684E-17, pi=3,14159265358979

Как вы могли заметить, к четвертому прогону мои цифры максимальны. И десятичный помогает только немного больше, но мне нужно МНОГО. Мой алгоритм зацикливается и добавляет.

Я думал об использовании строки, но моя проблема в том, что если у меня нет типа данных для хранения этих цифр, как мне преобразовать их в строку?

И я знаю, что люди делали это раньше, мне просто интересно, как...

Спасибо за любой совет!


person Landin martens    schedule 01.05.2011    source источник
comment
возможный дубликат десятичных чисел произвольной точности в C#   -  person kennytm    schedule 01.05.2011
comment
Используя десятичную дробь, вы получили: 3,1415926535897932384626433832, не более   -  person Arnaud F.    schedule 01.05.2011


Ответы (3)


Вы можете использовать сборку Swensen.BigInt.dll из CodeProject. Если вам нужна версия .net 2.0, вы можете загрузить ее здесь.

person oxilumin    schedule 01.05.2011
comment
Вы перепутали CodePlex с CodeProject ;-) - person Uwe Keim; 01.05.2011

Вы можете использовать BigInteger для хранения всего после запятой. .

person Daniel Rose    schedule 01.05.2011
comment
Проблема в том, что ему нужен .net 4.0. Если мне придется его использовать ... я думаю, что буду, но я бы предпочел способ, который поддерживает .net 2.0 и выше. - person Landin martens; 01.05.2011
comment
И даже тогда BigInteger проблематичен, поскольку он неизменяем, и поэтому вам нужно выделить много больших объектов. - person CodesInChaos; 01.05.2011

Используйте этот код, он работает как шарм

using System;
using System.Text;

class Solution
{
    static void Main(string[] args)
    {  
        BigNumber x = new BigNumber(100);
        BigNumber y = new BigNumber(100);
        x.ArcTan(16, 5);
        y.ArcTan(4, 239);
        x.Subtract(y);
        stopWatch.Stop();
        Console.WriteLine(x.Print());    
        Console.ReadLine();
    }
}
public class BigNumber {
    private UInt32[] number;
    private int size;
    private int maxDigits;

    public BigNumber(int maxDigits) {
      this.maxDigits = maxDigits;
      this.size = (int) Math.Ceiling((float)maxDigits * 0.104) + 2;
      number = new UInt32[size];
    }
    public BigNumber(int maxDigits, UInt32 intPart)
      : this(maxDigits) {
      number[0] = intPart;
      for (int i = 1; i < size; i++) {
        number[i] = 0;
      }
    }
    private void VerifySameSize(BigNumber value) {
      if (Object.ReferenceEquals(this, value))
        throw new Exception("BigNumbers cannot operate on themselves");
      if (value.size != this.size)
        throw new Exception("BigNumbers must have the same size");
    }
    public void Add(BigNumber value) {
      VerifySameSize(value);

      int index = size - 1;
      while (index >= 0 && value.number[index] == 0)
        index--;

      UInt32 carry = 0;
      while (index >= 0) {
        UInt64 result = (UInt64)number[index] + 
                        value.number[index] + carry;
        number[index] = (UInt32)result;
        if (result >= 0x100000000U)
          carry = 1;
        else
          carry = 0;
        index--;
      }
    }
    public void Subtract(BigNumber value) {
      VerifySameSize(value);

      int index = size - 1;
      while (index >= 0 && value.number[index] == 0)
        index--;

      UInt32 borrow = 0;
      while (index >= 0) {
        UInt64 result = 0x100000000U + (UInt64)number[index] - value.number[index] - borrow;
        number[index] = (UInt32)result;
        if (result >= 0x100000000U)
          borrow = 0;
        else
          borrow = 1;
        index--;
      }
    }
    public void Multiply(UInt32 value) {
      int index = size - 1;
      while (index >= 0 && number[index] == 0)
        index--;
    enter code here
      UInt32 carry = 0;
      while (index >= 0) {
        UInt64 result = (UInt64)number[index] * value + carry;
        number[index] = (UInt32)result;
        carry = (UInt32)(result >> 32);
        index--;
      }
    }
    public void Divide(UInt32 value) {
      int index = 0;
      while (index < size && number[index] == 0)
        index++;

      UInt32 carry = 0;
      while (index < size) {
        UInt64 result = number[index] + ((UInt64)carry << 32);
        number[index] = (UInt32) (result / (UInt64)value);
        carry = (UInt32)(result % (UInt64)value);
        index++;
      }
    }
    public void Assign(BigNumber value) {
      VerifySameSize(value);
      for (int i = 0; i < size; i++) {
        number[i] = value.number[i];
      }
    }

    public string Print() {
      BigNumber temp = new BigNumber(maxDigits);
      temp.Assign(this);

      StringBuilder sb = new StringBuilder();
      sb.Append(temp.number[0]);
      sb.Append(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator);

      int digitCount = 0;
      while (digitCount < maxDigits) {
        temp.number[0] = 0;
        temp.Multiply(100000);
        sb.AppendFormat("{0:D5}", temp.number[0]);
        digitCount += 5;
      }

      return sb.ToString();
    }
    public bool IsZero() {
      foreach (UInt32 item in number) {
        if (item != 0)
          return false;
      }
      return true;
    }

    public void ArcTan(UInt32 multiplicand, UInt32 reciprocal) {
      BigNumber X = new BigNumber(maxDigits, multiplicand);
      X.Divide(reciprocal);
      reciprocal *= reciprocal;

      this.Assign(X);

      BigNumber term = new BigNumber(maxDigits);
      UInt32 divisor = 1;
      bool subtractTerm = true;
      while (true) {
        X.Divide(reciprocal);
        term.Assign(X);
        divisor += 2;
        term.Divide(divisor);
        if (term.IsZero())
          break;

        if (subtractTerm)
          this.Subtract(term);
        else
          this.Add(term);
        subtractTerm = !subtractTerm;
      }
    }
}
person Eric He    schedule 28.06.2015