Большинство людей, изучающих компьютерное программирование, часто начинают с простых математических программ. Сложение и вычитание чисел должно быть относительно простым, верно?

Допустим, вы пытаетесь сравнить два числа в Java. Взгляните на следующий код:

double a = 0.7; 
double b = 0.9; 
double x = a + 0.1; 
double y = b - 0.1; 
if (x == y) {
    System.out.println("x and y are the same!");
} else {
    System.out.println("x and y are not the same :(");
}

Давайте сначала проработаем это мысленно. Переменная x равна a + 0,1. Переменная y равна b -0,1. Поскольку a равно 0,7, x должно равняться 0,8. А поскольку b равно 0,9, y также должно быть равно 0,8.

В этом примере x и y должны быть равны друг другу.

Тем не менее, это не так. Давайте углубимся в то, почему это происходит.

После того, как вы распечатаете x и y, вы обнаружите следующее.

x = 0.7999999999999999
y = 0.8

Хорошо… это выглядит правильно. 0,7999999999999 очень близко к 0,8. Ну, что здесь пошло не так?

Проблема здесь заключается в том, как десятичные числа хранятся в компьютерах. Компьютер использует основание 2 (двоичная система счисления) вместо традиционной системы с основанием 10.

В основе 10 у нас есть разряд единиц, разряд десятков, разряд сотых и так далее. Однако в базе 2 у нас есть разряд единиц, разряд двоек, разряд четверок, разряд восьмерок и так далее. Так что, если мы хотим представить 5 по основанию 2, нам нужна 1 в разряде четверок и 1 в разряде единиц, или «101».

Хорошо, тогда как мы представляем десятичные дроби? Как и в научной записи, вместо ЧИСЛО* 10^X мы можем использовать ЧИСЛО*2^Х для основания 2. Идя наоборот, теперь у нас есть один половинный разряд, один четверть разряд, один восьмой разряд и так далее. на.

Поэтому, если нам нужно представить 0,5 в двоичном виде, мы можем сделать это с помощью 0,1 (например, 1 * 2 ^-1). Если нам нужно представить 0,25 в двоичном виде, мы можем сделать это с помощью 0,01 (например, 1*2^-2).

Но время от времени вы получаете число, которое невозможно представить с помощью этой кодировки.

В нашем первом примере мы добавили число 0,1. В двоичном виде это число можно записать как 0,00011 повторений. Точно так же в базе 10 дробь 1/3 записывается как 0,33333 повторения. Математически это эквивалентно, но у компьютеров нет бесконечной памяти для повторения десятичных дробей. В конечном итоге это приводит к (хотя и несколько небольшой) потере точности.

Я не специалист и могут быть ошибки. Если вы заметили что-то не так с моим сообщением в блоге, сообщите мне, и я буду рад исправить любые проблемы :). Я закончил этот пост в блоге для университетского курса.