BigInteger, анализирующий научную нотацию с показателем больше 1000, приводит к 9999

#c# #biginteger

#c# #biginteger

Вопрос:

Я пытался понять, почему этот код, похоже, работает так, как он работает. Для меня это похоже на ошибку в BigInteger классе, но я могу ошибаться.

 using System.Numerics;
using System.Globalization;

BigInteger resu<
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

Комментарии:

1. «независимо от того, какое число я использую, мантисса всегда равна 9999». Вы имеете в виду показатель ?

2. Вот ваша проблема , все, что превышает 1000, получает показатель 9999

3. Теперь, когда мы это знаем, любое решение будет зависеть от того, что вы на самом деле пытаетесь сделать или, в частности, что вам нужно сделать.

4. Да, это определенно так, спасибо. По сути, то, что я пытаюсь сделать, это проанализировать кучу этих больших чисел в том же формате 0.00e0000, чтобы я мог использовать их как BigIntegers для сравнения и математических операций. Возможно, я смогу придумать умный способ разбить их на части, потому что я не думаю, что проблема в основном связана с классом BigInteger, а с этой реализацией TryParse .

Ответ №1:

Причина, по которой это не работает, заключается не столько в ошибке как таковой, сколько в ограничении ParseNumber

 if (exp > 1000)
{
   exp = 9999;
   while (ch >= '0' amp;amp; 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
  

Полная демонстрация здесь

Примечание : это не решение каждой проблемы, ему не хватает подходящей степени отказоустойчивости, и это только пример возможного решения.