在C#中,我需要使用非常大(和非常小)的数字,其中decimal和double不够准确,BigInteger无法存储数字的分数。
我想让数字具有尽可能长的组件,即特征和尾数,因为内存(最好是硬盘驱动器)空间允许。
是否有人有类或者系统类型是否真的很大。
我需要能够加,减,除,模,平方,平方根,sin,cos,tan(和它们的反转)并乘以数字。几乎是标准十进制/双精度的完整功能(如果我错过了任何一个)。
无穷无需代表,但这将是一个加号*!
一个非常小的数字的例子是:
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
以及非常大的数字的例子是:
1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
和
-1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
我更喜欢ToString()以上述形式返回数字。科学记数法是可以接受的,但绝不是首选。
四个最重要的要求是:
BigInteger不是一个可接受的答案。
*如果无穷无尽,那么我只需要尽可能地实现它,例如(无穷大/无穷大= 1),(0 /无穷大= 0)等。
答案 0 :(得分:6)
使用BigInteger。它代表一个任意大的有符号整数。
答案 1 :(得分:3)
它不符合规范,但我会将BigInteger
用于整数,将decimal
用于小数。
BigInteger(理论上)有no upper or lower bounds.
十进制精确到28 significant figures
答案 2 :(得分:2)
您可能需要查看可能在CodePlex上找到的BigRational类。
它将数字表示为两个BigIntegers的比率。
ToString方法不符合您的要求,因为它将数字格式化为比率(分子/分母)。但是,由于源代码存在,你可以疯狂地实现IFormattable。
答案 3 :(得分:1)
你在这里要求的两件事在同一领域目前是不可能的,而你的数字并没有丢失一些精确度。有一点是无限。另一件事涉及数字。例如,除非你在某处画一条线或者包含某种类型的模式匹配,这种模式匹配倾向于某个数字的截止,否则你无法实现“无穷大”。
但是,由于你的数字非常大,而且数字非常精确,并且由于没有可以同时支持的已知数字数据类型,我建议你自己实现。只需复制您已有的数字结构的功能,并将它们与您的需求结合起来。
我的一般想法是创建自己的数值数据类型,对于整数使用类似BigInteger的数字类型,对于非常精确的数字,使用类似Decimals的类似数据。或者你也应该看一下BigRational因为它们具有一些基本的加法,减法等功能,而且它们也有Numerator和Denominator属性。
我使用Decimals而不是Doubles之类的其他原因是Decimal类型是固定点而Doubles是浮点数。例如,浮点是0.1 + 0.2 = 0.30000000000000004的原因。但只有在你完全实现自己的系统时才考虑这个。
tl; dr:创建自己的类,结合BigInteger和BigRational。
答案 4 :(得分:1)
为了我的学习目的,我创建了可以管理大量数字的类,如果需要可以使用它。这个课有一些问题,我不保证它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);
}
}
}