BigInteger 解析指数大于1000的科学计数法结果为9999

BigInteger Parsing scientific notation with an exponent larger than 1000 results in 9999

我一直在纠结为什么这段代码看起来像它那样工作。对我来说,它看起来像是 BigInteger class 中的错误,但我可能是错的。

using System.Numerics;
using System.Globalization;

BigInteger result;
if (!BigInteger.TryParse("2.36e6007", NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint, null, out result)) result = 0;
Debug.WriteLine(result.ToString("0.00e0000"));

我总是得到 2.36e9999 作为结果,无论我使用什么数量级总是 9999。我不确定这是一个错误还是我在这里做错了什么。我在解析后尝试了一个断点并检查了值,它确实有 9999 零,所以如果它是一个错误,它在 BigInteger.TryParse

这不起作用的原因与其说是错误 本身 ,不如说是 ParseNumber

中的限制
if (exp > 1000)
{
   exp = 9999;
   while (ch >= '0' && ch <= '9')
   {
      ch = *++p;
   }
}

如您所见,任何超过 1000 指数 都将默认为 9999 的指数。

一种方法(取决于您的需要)是自己解析指数并从其组成部分创建 BigInteger。这样做的缺点是它不会处理超出其非常狭窄范围的任何变化(您需要添加胡椒和盐来调味)。它也可能会慢很多。

给定

public static (decimal multiplier, int exponent) Decompose(string value)
{
   var split = value.Split('e');
   return (decimal.Parse(split[0]), int.Parse(split[1]));
}
public static int GetDecimalPlaces(decimal value) 
   => BitConverter.GetBytes(decimal.GetBits(value)[3])[2];

public static BigInteger ParseExtended(string value)
{
   var (multiplier, exponent) = Decompose(value);

   var decimalPlaces = GetDecimalPlaces(multiplier);
   var power = (int) Math.Pow(10, decimalPlaces);

   return (BigInteger.Pow(10, exponent) * (int) (multiplier * power)) / power;
}

用法

Console.WriteLine(ParseExtended("2.36e6007").ToString("0.00e0000"));

输出

2.36e6007

Full Demo Here

注意:这不是对所有问题的解决方案,它缺乏适当的容错量,只是一个例子一个可能的解决方案。