C # - Увеличение двойного значения (1.212E + 25) - PullRequest
4 голосов
/ 28 мая 2010

У меня есть двойное значение, равное 1.212E + 25

Когда я выкидываю это в текст, я делаю myVar.ToString ("0000000000000000000000")

Проблема в том, что даже если я использую myVar ++ 3 или 4 раза, значение остается неизменным.

Почему это?

Ответы [ 5 ]

3 голосов
/ 28 мая 2010

Это потому, что точность двойного недостаточно. Он просто не может содержать столько значащих цифр.

Он не будет длинным, но, вероятно, десятичным.

Но ... Вам действительно нужен этот уровень точности?

2 голосов
/ 28 мая 2010

Чтобы развернуть другой ответ, наименьшее увеличение, которое вы можете сделать до двойного, составляет одну единицу в последнем месте, или ULP, поскольку double - это тип с плавающей запятой, тогда размер ULP изменяется, при 1E + 25 он будет быть около 1E + 10.

Как вы можете видеть по сравнению с 1E + 10, увеличение на 1 действительно может ничего не добавлять. это именно то, что будет делать double, поэтому не имеет значения, если вы попробуете это 10 ^ 25 раз, оно все равно не увеличится, если вы не попытаетесь увеличить по крайней мере на 1 ULP

Если увеличение на ULP полезно, вы можете сделать это, приведя биты к длинному, и обратно - это быстрый метод расширения, чтобы сделать это

  public static double UlpChange(this double val, int ulp)
  {
    if (!double.IsInfinity(val) && !double.IsNaN(val))
    {
      //should probably do something if we are at max or min values 
      //but its not clear what
      long bits = BitConverter.DoubleToInt64Bits(val);
      return BitConverter.Int64BitsToDouble(bits + ulp);
    }
    return val;
  }
1 голос
/ 28 мая 2010

double (Double) содержит около 16 цифр точности и long (Int64) около 18 цифр.

Похоже, что ни один из них не обладает достаточной точностью для ваших нужд.

Однако decimal (Decimal) содержит до 30 цифр точности. Хотя это кажется достаточно большим для ваших нужд, я бы порекомендовал осторожность в случае, если ваши требования возрастут еще больше. В этом случае вам может понадобиться сторонняя цифровая библиотека.

Связанные записи StackOverflow:
Как я могу представить очень большое целое число в .NET?
Большие целые числа в C #

1 голос
/ 28 мая 2010

Возможно, вы захотите прочитать Руководство с плавающей запятой , чтобы понять, как doubles работает.

Как правило, double имеет только около 16 десятичных цифр точности. При величине 10 ^ 25 увеличение на 1,0 ниже порога точности и теряется. Из-за двоичного представления это может быть неочевидно.

0 голосов
/ 28 мая 2010

Наименьшее приращение, которое сработает, равно 2 ^ 30 + 1, которое фактически увеличит двойное значение на 2 ^ 31. С LINQPad вы можете довольно легко протестировать подобные вещи:

double inc = 1.0;
double num = 1.212e25;
while(num+inc == num) inc*=2;

inc.Dump(); //2147483648 == 2^31
(num+inc == num).Dump(); //false due to loop invariant
(num+(inc/2.0) == num).Dump();//true due to loop invariant
(num+(inc/2.0+1.0) == num).Dump();//false - 2^30+1 suffices to change the number
(num+(inc/2.0+1.0) == num + inc).Dump();//true - 2^30+1 and 2^31 are equiv. increments
((num+(inc/2.0+1.0)) - num == inc ).Dump();//true - the effective increment is 2^31

Поскольку double по сути является двоичным числом с ограниченной точностью, это означает, что наименьшее возможное приращение само по себе всегда будет степенью двойки (это приращение может быть определено непосредственно из битовой структуры двойного числа, но, вероятно, оно более четкое сделать это с помощью цикла, как описано выше, поскольку он переносим между float, double и другими представлениями с плавающей запятой (которых нет в .NET).

...