Luffy1
@Luffy1
Студент, Junior .NET programmer

Почему при сложении 0.001 типа float или doable 1000 раз через несколько нулей после запятой появляются ещё числа из ниоткуда и как это решить?

static void Main()
    {
      float a = 0.001f;
      for (int i = 0; i < 1000; i++)
      {
        a += 0.001f;
      }
      Console.Write(a);
    }

Вывело: 1.0009907
Откуда взялась часть "9907", если должна была получится просто единица?
Прохожу шажками(проходы по циклу):
1. 0.002
2. 0.003
3. 0.004
4. 0.00500000035 - вот, что это такое?
5. 0.00600000052 - и сново
6. 0.00700000068 - и опять
Что это такое? Почему так происходит? Откуда берутся эти "лишние" числа?
Так же с double:
Думал избавлюсь от проблемы, ибо у double повышенная точность(обычно он как раз таки и используется при расчётах).
static void Main()
    {
      double a = 0.001;
      for (int i = 0; i < 1000; i++)
      {
        a += 0.001;
      }
      Console.Write(a);
    }

Вывело: 1.0010000000000006
Прохожу шажками(проходы по циклу):
1. 0.002
2. 0.003
3. 0.004
4. 0.005 - Оооо, тут уже всё нормально
5. 0.006 - и тут тоже
...
7. 0.0090000000000000011 - пошло, поехало! Опять!
Почему так происходит? Откуда берутся эти "лишние" числа?
Как это связано с двоичной системой счисления?(вроде, правильное понятие сказал, тут могу ошибаться)
Как эту проблему можно решить или как её можно избежать?
Как мне, например, если я после "такого" сложения хочу проверить, что вышло число 1, а вышла такая чупакабра? Явным преобразованием в целочисленный тип?
  • Вопрос задан
  • 267 просмотров
Решения вопроса 3
gdt
@gdt
Программист
И ни одного пояснения :)
Если вам нужно, чтобы работало так, как вы ожидаете - воспользуйтесь замечательным советом Бобби Шифер .
Если объяснить на пальцах - есть два способа хранить числа с точкой - fixed point (фиксированная точка) и floating point (плавающая точка). У себя в примере вы используете тип данных с плавающей точкой (неспроста он называется float, а double - это float с двойной точностью, только и всего). Грубо говоря, числа с плавающей точкой представляются так: M*10^E, т. е. в памяти два значения M и E просто следуют друг за другом. К сожалению, компьютеры используют двоичную систему счисления, и далеко не всегда то, что можно просто записать в десятичной системе счисления - настолько же просто записать в двоичной, и наоборот. С учётом того, что объём памяти, выделяемый под хранение мантиссы, ограничен - она округляется до ближайшего двоичного представления, что после перевода назад, в десятичную систему счисления, и даёт такой, на первый взгляд, контринтуитивный результат.
Для разнообразия можете попробовать сложить очень маленькое и очень большое число.
Ответ написан
gbg
@gbg
Баянист. Тамада. Услуги.
Храните деньги в сберегательной кассе в DECIMAL!
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы