Почему разница в вычислениях/кастинге между (long)z и (long)(x+y)?

Рейтинг: 1Ответов: 1Опубликовано: 14.04.2023

Тестирую на .NET Framework 4.5.2 x86

float test1 = 1.3F,
      test2 = 5.2F;
float i2_float = test1 * 100,
      i3_float = test2 * 100;
long i1 = (long)i2_float;
long i2 = (long)i3_float;

Для первого варианта получаю следующие значения: i1=130, i2=520

float test1 = 1.3F,
      test2 = 5.2F;
long i1 = (long)(test1 * 100);
long i2 = (long)(test2 * 100);

Для второго получаю следующие значения: i1=129, i2=519

Почему получаю разные результаты для i1/i2 если результат операций test * 100 в обеих вариантах равен float и явно кастится в long?

Ответы

▲ 3Принят

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

Наверняка воспроизводимый код у меня не получилось сделать, чтобы показать, что там внутри, но по факту, там что-то типа 1.29999999998 вместо 1.3, которое вы умножаете на 100, затем приведением к long отбрасываете дробную часть, и получается 129. То же самое для второго числа.

Почему float i2_float = test1 * 100 работает: потому что компилятор умный и он решил оптимизировать ваше умножение как работу с константами, то есть ваш код скомпилируется во что-то типа long i1 = 130L; и никаких упоминаний в скомпилированном коде о float не будет. То есть финальное значение до какой-то степени будет вычислено на этапе компиляции. Точно так же как если бы у вас было const float test1 = 1.3F.

Почему разница результата в двух примерах: компилятор в .NET 4.x недостаточно умный, чтобы оптимизировать оба примера, у него хватило алгоритмов только на 1 из двух, а вот компилятор в .NET 6 - уже умнее и смог распознать и оптимизировать оба случая.