【问题标题】:Incredibly huge and incredibly small numbers (not just integers) in C#C# 中令人难以置信的巨大和令人难以置信的小数字(不仅仅是整数)
【发布时间】:2015-07-29 13:23:22
【问题描述】:

在 C# 中,我需要处理非常大(和非常小)的数字,其中小数和双精度不够准确,而且 BigInteger 无法存储数字的分数。

我希望数字具有尽可能长的组成部分,即特征和尾数,只要内存(最好是硬盘)空间允许。

是否有人有一个类或者有一个非常大的数字的系统类型。

我需要能够加、减、除、模、平方、平方根、sin、cos、tan(以及它们的倒数)和乘法。几乎是标准 Decimal/Double 的完整功能(以防我遗漏任何内容)。

不需要表示无穷大,但它会是一个加号*!

一个非常小的数字的例子是:

0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001

非常大的数字示例如下:

1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001

-1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001

我更喜欢 ToString() 以上述形式返回数字。科学记数法是可以接受的,但绝不是首选。

四个最重要的要求是:

  1. 号码的准确性
  2. 至少,基本的数学运算可以 应用;乘法、除法、加法和减法
  3. 数量只能受备用内存和硬盘大小的限制。
  4. 数字必须以字符串形式输出 特征、小数点和尾数,例如100.23、100 或 0.000000054
  5. 应该支持尾数中的递归

BigInteger 不是可接受的答案。

*如果实现了无穷大,那么我只需要尽可能地实现它,例如(infinity / infinity = 1), (0 / infinity = 0) 等

【问题讨论】:

  • 寻找BigInteger
  • BigInteger 仅适用于整数。使用 BigInteger 将特征和尾数存储在类中的解决方案,或者可能是浮点实现将是完美的,但 BigInteger 本身不是解决方案。
  • 我说您的要求#3减少寻找解决周围0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001的概率。跨度>
  • @OldFart 很有幽默感,哈哈

标签: c# class math


【解决方案1】:

使用BigInteger。它表示一个任意大的有符号整数。

【讨论】:

  • 使用Tuple<BigInteger, int>,您可以保存科学计数法中的所有值。
  • @fubo “double 不够准确”并不一定意味着 OP 想要存储分数 - double 也不够准确,无法存储许多大整数。
  • @Rawling OP 最初评论了“0.000000001 怎么样”,但后来删除了该评论。
  • @9Deuce 我向你保证我不会反对你,只是告诉你我的答案来自哪里以及为什么在你指出之前我不介意小数。
  • @9Deuce:小数不够准确:分数中出现错误。
【解决方案2】:

它不符合规范,但我会使用 BigInteger 表示整数,使用 decimal 表示小数。

BigInteger(理论上)有no upper or lower bounds.

小数精确到28 significant figures

【讨论】:

  • 小数不够准确:分数中出现错误。目前正在调查 Adam 建议的 BigRational
【解决方案3】:

您可能想查看BigRational 类,它可以在 CodePlex 上找到。

它将数字表示为两个 BigInteger 的比率。

ToString 方法不符合您的要求,因为它将数字格式化为比率(分子/分母)。但是,由于源代码在那里,您可以疯狂地实现 IFormattable。

【讨论】:

    【解决方案4】:

    您在这里要求的 2 件事目前在同一个域中是不可能的,而不会丢失您的数字的一些精度。一件事是无穷大。另一件事处理数字。例如,除非您在某处画一条线,或者您包含某种模式匹配,这种匹配趋向于在某个数字处截断,否则您无法实现“无穷大”。

    但是,由于您要处理非常大的数字和极其精确的小数字,并且由于没有已知的数字数据类型可以同时支持两者,我建议您自己实现。只需复制您已有的数字结构的功能并将它们组合到您的需要。

    我的总体想法是创建您自己的数字数据类型,使用类似BigInteger 的整数表示整数,使用类似Decimals 表示极其精确的数字。或者你也应该看看BigRational,因为它们具有一些基本的加法、减法等功能,并且它们还具有分子和分母属性。

    我使用小数而不是像Doubles 这样的其他东西的原因是小数类型是定点的,而双精度是浮点数。例如,浮点数是 0.1 + 0.2 = 0.30000000000000004 的原因。但只有在您完全实现自己的系统时才考虑这一点。

    tl;dr:结合 BigInteger 和 BigRational 创建您自己的类。

    【讨论】:

    • 另外,显然浮点计算比 Big* 计算更快。因此,请考虑研究您实际需要多少精度。 stackoverflow.com/questions/5473136/…
    • 我只需要在人类理解的范围内表现无限。 IE。我们知道无穷大的某些特征是真实的,例如无穷的倍数等于无穷,零除以无穷等于零。这些天我们有巨大的硬盘驱动器,我希望那个空间用来存储非常大的数字。当 Infinity 可以是具有属性和方法的类时,不必以位形式存储。坦率地说,在当前计算机上,大数的精度以小数结尾是荒谬的。
    【解决方案5】:

    为了我的学习目的,我创建了可以管理大量数字的类,如果你愿意,可以使用它。这个类有一些问题,我不保证它可以 100% 工作(但我在许多场景下测试它并且一切正常)。除法运算符也存在性能问题(尝试降低 divPrecision 以获得更快的速度),我现在没有时间学习除法算法。我确信有更复杂(可能更好)的方法来制作这样的课程,但这是我根据你的想法在几个小时内完成的。

    using System;
    using System.Linq;
    using System.Numerics;
    
    namespace RealNumber
    {
        class RealNum
        {
            private BigInteger m = 0;
            private int w = 0;
    
            private static int divPrecision = 100000;
            private static char[] trimStartChar = { '0', '-' };
            private static char[] trimEndChars = { '.', ',' };
    
            public RealNum()
            {
    
            }
    
            public RealNum(BigInteger _m, int _w = 0 )
            {
                w = _w;
                m = _m;
    
                miniW();
            }
    
            public RealNum(string number)
            {
                number = number.Trim();
    
                System.Text.RegularExpressions.Regex textValidator = new System.Text.RegularExpressions.Regex(@"^-?[0-9]+([,.][0-9]+)?$");
    
                if (!textValidator.IsMatch(number))
                {
                    throw new FormatException();
                }
    
                bool minSig = number.Contains('-');
    
                number = number.TrimStart(trimStartChar);
                if (number.Contains('.') || number.Contains(','))
                {
                    number = number.TrimEnd(trimStartChar);
                    number = number.TrimEnd(trimEndChars);
                }
    
                if (string.IsNullOrEmpty(number))
                {
                    return;
                }
    
                char[] splitChars = { '.', ',' };
    
                string[] idnum = number.Split(splitChars, StringSplitOptions.None);
                if (string.IsNullOrEmpty(idnum[0]))
                    idnum[0] = "0";
    
                if(idnum.Length==1)
                {
                    m = BigInteger.Parse(idnum[0]);
                }
                else
                {
                    w = idnum[1].Length;
                    m = BigInteger.Parse(idnum[0]) * BigInteger.Pow(10, idnum[1].Length) + BigInteger.Parse(idnum[1]);
                }
    
                if (minSig)
                    m = -m;
    
                miniW();
    
            }
    
            private void miniW()
            {
                while( m % (new BigInteger(10)) == 0 && m > 0 )
                {
                    m = m / 10;
                    w--;
                }
            }
    
    
            public override string ToString()
            {
                string num = m.ToString();
    
                if (w > 0)
                {
    
                    if(num.Length - w <= 0)
                    {
                        string zeros = new string('0', -num.Length + w + 1);
                        num = zeros + num;
                    }
    
                    num = num.Insert(num.Length - w, ".");
                }
                else if(w < 0)
                {
                    string zeros = new string('0', -w);
                    num = num + zeros;
                }
    
                return num;
            }
    
    
            public static RealNum operator+ (RealNum a, RealNum b)
            {
    
                int wSub = a.w - b.w;
    
                if(wSub<0)
                {
                    wSub = -wSub;
                    a = System.Threading.Interlocked.Exchange(ref b, a);
                }
    
                return new RealNum(a.m + b.m * BigInteger.Pow(10, wSub), a.w);
    
            }
    
            public static RealNum operator -(RealNum a, RealNum b)
            {
                int wSub = a.w - b.w;
    
                if (wSub < 0)
                {
                    wSub = -wSub;
                    a = System.Threading.Interlocked.Exchange(ref b, a);
                    return new RealNum(b.m * BigInteger.Pow(10, wSub) - a.m, a.w);
                }
    
                return new RealNum(a.m - b.m * BigInteger.Pow(10, wSub), a.w);
    
            }
    
            public static RealNum operator *(RealNum a, RealNum b) => 
                new RealNum(a.m * b.m, a.w+b.w);
    
            public static RealNum operator /(RealNum a, RealNum b)
            {
    
                int precision = RealNum.divPrecision;
                if (precision <= b.w)
                    precision = b.w+10;
                int aSubSup = 0;
                int aSub;
                if (a.w < 0)
                {
                    aSubSup = -a.w;
                    aSub = precision;
                }
                else
                {
                    aSub = precision - a.w;
                }
    
                BigInteger am = a.m * BigInteger.Pow(10, aSubSup) * BigInteger.Pow(10, aSub);
    
                return new RealNum(am/b.m, precision-b.w);
    
            }
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-10-10
      • 1970-01-01
      • 1970-01-01
      • 2019-06-05
      • 1970-01-01
      • 2019-05-20
      • 2013-01-06
      • 2018-08-05
      • 2016-12-05
      相关资源
      最近更新 更多