Рассмотрим следующий код C #:
double result1 = 1.0 + 1.1 + 1.2;
double result2 = 1.2 + 1.0 + 1.1;
if (result1 == result2)
{
...
}
result1 всегда должен равняться result2, верно? Дело в том, что это не так. result1 равен 3.3, а result2 равен 3.3000000000000003. Единственная разница - порядок констант.
Я знаю, что двойники реализованы таким образом, что могут возникнуть проблемы с округлением. Я знаю, что могу использовать десятичные дроби, если мне нужна абсолютная точность. Или что я могу использовать Math.Round () в моем операторе if. Я просто ботаник, который хочет понять, что делает компилятор C #. Кто-нибудь может мне сказать?
Edit:
Спасибо всем, кто до сих пор предлагал прочитать арифметику с плавающей запятой и / или рассказал о неточности, присущей тому, как процессор обрабатывает данные, удваивается. Но я чувствую, что основной смысл моего вопроса все еще остается без ответа. Который - моя вина, что я не правильно сформулировал это. Позвольте мне сказать это так:
Если разбить приведенный выше код, я ожидаю, что будут выполняться следующие операции:
double r1 = 1.1 + 1.2;
double r2 = 1.0 + r1
double r3 = 1.0 + 1.1
double r4 = 1.2 + r3
Предположим, что в каждом из вышеперечисленных добавлений была ошибка округления (номер e1..e4). Таким образом, r1 содержит ошибку округления e1, r2 содержит ошибки округления e1 + e2, r3 содержит e3 и r4 содержит e3 + e4.
Теперь я не знаю, как именно происходят ошибки округления, но я ожидал, что e1 + e2 будет равно e3 + e4. Ясно, что это не так, но мне это кажется каким-то неправильным. Другое дело, что когда я запускаю приведенный выше код, я не получаю никаких ошибок округления. Именно это заставляет меня думать, что компилятор C # делает что-то странное, а не процессор.
Я знаю, что спрашиваю много, и, возможно, лучший ответ, который кто-либо может дать, - это пойти и сделать докторскую степень в области проектирования процессоров, но я просто подумал, что спросить.
Редактировать 2
Глядя на IL из моего исходного примера кода, становится ясно, что это делает не компилятор, а компилятор:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] float64 result1,
[1] float64 result2)
L_0000: nop
L_0001: ldc.r8 3.3
L_000a: stloc.0
L_000b: ldc.r8 3.3000000000000003
L_0014: stloc.1
L_0015: ret
}
Компилятор складывает для меня числа!