我想在一个应用程序(增量游戏)中显示非常大的数字。指数可以大于100,000(十万),因此double
或float
将满足其限制。我知道BigInteger
类型,但我读到它可能很慢,并且我不需要在有效位数上超过5 digts的精度,因此它可能不是一个好选择
数字的示例可以是1.2345 * 10 ^ 100000。在这种情况下,我不在乎第5位之后的任何小数(精度在5-15 digt之间的任何地方都可以)
我需要在30ms循环中对该数字执行多项操作(乘法,加法,乘方,对数),因此它应该很快。我怎样才能做到这一点呢?有图书馆吗?还是需要自己做?
如果我能用科学,工程,字母,标准(百万,十亿,...,十亿,八十万,非百万)等不同的符号表示数字,那也很好。
答案 0 :(得分:1)
我不知道是否已经有一个用于此的库,但是您可以尝试为LargeNumbers编写自己的类:
class LargeNumber
{
double Value;
int Mantissa;
}
编辑: 是的,您必须了解指数是如何工作的,这并不琐碎,但也不太困难。
加法运算的一些数学示例,例如:
firstNumber.Mantissa> secondNumber.Mantissa> 0:
...
var expDifference = firstNumber.Mantissa - secondNumber.Mantissa;
if(expDifference > 5)
{
return firstNumber;
}
if(expDifference < 5)
{
return new LargeNumber
{
Value = firstNumber.Value*(10^expDifference) + secondNumber.Value,
Mantissa= firstNumber.Mantissa
}
}
...
答案 1 :(得分:0)
一种近似表示巨大数字的想法是仅使用数字的对数。 通常的算术运算非常简单地转换为对数。我们利用以下公式:
最复杂的是加法/减法(从数字上讲,选择较大的数字为 a 是有利的)
由于对数仅定义为严格的正数,因此为了表示负数和零,我们必须将符号添加为额外的簿记变量。
总共,我提出了以下类,实现加,减,一元加减,乘法,除法,对数,求幂和一整套比较运算符:
struct HugeNumber : IEquatable<HugeNumber>, IComparable<HugeNumber>
{
private int _sign; // -1, 0 or +1
private double _log;
private HugeNumber(int sign, double log)
{
_sign = sign;
_log = log;
}
public static implicit operator HugeNumber(double number)
{
if (number > 0.0)
return new HugeNumber(1, Math.Log10(number));
else if (number < 0.0)
return new HugeNumber(-1, Math.Log10(-number));
else
return new HugeNumber(0, 0.0);
}
public static HugeNumber operator*(HugeNumber n1, HugeNumber n2)
{
return new HugeNumber(n1._sign * n2._sign, n1._log + n2._log);
}
public static HugeNumber operator/(HugeNumber n1, HugeNumber n2)
{
return new HugeNumber(n1._sign * n2._sign, n1._log - n2._log);
}
public static HugeNumber operator+(HugeNumber n)
{
return n;
}
public static HugeNumber operator-(HugeNumber n)
{
return new HugeNumber(-n._sign, n._log);
}
public static HugeNumber operator+(HugeNumber n1, HugeNumber n2)
{
if (n1._sign == 0)
{
return n2;
}
else if (n2._sign == 0)
{
return n1;
}
else
{
if (n1._log > n2._log)
{
return new HugeNumber(n1._sign, n1._log + Math.Log10(1.0 + n1._sign * n2._sign * Math.Pow(10, n2._log - n1._log)));
}
else
{
return new HugeNumber(n2._sign, n2._log + Math.Log10(1.0 + n1._sign * n2._sign * Math.Pow(10, n1._log - n2._log)));
}
}
}
public static HugeNumber operator-(HugeNumber n1, HugeNumber n2)
{
return n1 + -n2;
}
public double Log10()
{
if (_sign <= 0)
throw new ArgumentOutOfRangeException();
return _log;
}
public HugeNumber Pow(double exponent)
{
if (_sign < 0)
throw new ArgumentOutOfRangeException();
return new HugeNumber(_sign, exponent * _log);
}
public HugeNumber Abs()
{
if (_sign >= 0)
return this;
return new HugeNumber(1, _log);
}
public override string ToString()
{
if (_sign == 0)
return "0";
else
return string.Format("{0}{1}E{2:+0;-#}", _sign < 0 ? "-" : "", Math.Pow(10, _log - Math.Floor(_log)), Math.Floor(_log));
}
public bool Equals(HugeNumber n)
{
if (_sign == 0)
return n._sign == 0;
return _sign == n._sign && _log == n._log;
}
public override bool Equals(object obj)
{
if (obj is HugeNumber n)
return Equals(n);
return false;
}
public override int GetHashCode()
{
if (_sign == 0)
return 0;
return _log.GetHashCode();
}
public int CompareTo(HugeNumber n)
{
if (_sign > n._sign)
return 1;
else if (_sign < n._sign)
return -1;
else if (_sign == 0)
return 0;
else
return _sign * _log.CompareTo(n._log);
}
public static bool operator<(HugeNumber n1, HugeNumber n2) => n1.CompareTo(n2) < 0;
public static bool operator<=(HugeNumber n1, HugeNumber n2) => n1.CompareTo(n2) <= 0;
public static bool operator>(HugeNumber n1, HugeNumber n2) => n1.CompareTo(n2) > 0;
public static bool operator>=(HugeNumber n1, HugeNumber n2) => n1.CompareTo(n2) >= 0;
public static bool operator==(HugeNumber n1, HugeNumber n2) => n1.Equals(n2);
public static bool operator!=(HugeNumber n1, HugeNumber n2) => !n1.Equals(n2);
}
用法:
HugeNumber n = 10;
Console.WriteLine(n.Pow(10000)); // prints 1E+10000