Будет ли результат деления двух чисел с одинаковым соотношением всегда одинаковым? - PullRequest
1 голос
/ 21 апреля 2019

a - это integer.
b также является integer, но объявлено как double.
c = a/b и c также объявлены как double.

И есть a2, b2, c2, с правилами, аналогичными a, b, c.
Кроме того, в терминах десятичной алгебры две группы чисел удовлетворяют: a / b = a2 / b2, (например, 8 / 18.0 = 12 / 27.0) .

Вопросы:

  • В компьютере ( двоичный ), c и c2 всегда будут одинаковыми?
    например
    111 / 135.0 = 0.8222222222222222
    333 / 405.0 = 0.8222222222222222
    

(Я предполагаю, что да, поскольку все целые числа могут быть представлены в двоичном виде с ограниченной цифрой, но не совсем уверены, что это будет иначе, когда дело доходит до деления в компьютере.)


@ Update

Предположим, что компьютер / язык использует 32 бита для целых и 64 бита для двойного.

(Кстати, этот вопрос возникает при написании тестового примера, не уверен, что достаточно просто использовать ==, или разрешена небольшая дельта (= (expected - actual) / actual), например, +/- 0.000001).

1 Ответ

4 голосов
/ 21 апреля 2019

Резюме

Да, если:

  • a и a2 - 32-разрядные целые числа,
  • b и b2 являются ненулевыми значениями Java double, а
  • a / b = a2 / b2,

тогда a / b равно a2 / b2. (Обратите внимание, что a / b обозначает арифметику действительных чисел, тогда как a / b обозначает арифметику с плавающей точкой. 4 / 3 точно равно 1 is, а 4./3 равно 1,3333333333333332593184650249895639717578887939453125.)

Доказательство

Согласно комментарию автора, это для Java, которая использует IEEE 754, включая базовую 64-битную двоичную с плавающей точкой IEEE-754 для double.

Основным свойством большинства операций с плавающей запятой является то, что вычисляемый результат представляет собой результат действительного числа, округленный до ближайшего значения, представляемого в формате с плавающей запятой. Следствием этого является:

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

(Существуют различные правила округления. В Java используются округления до ближайших связей к четным, что означает использование ближайшего представимого значения, а при наличии связи - кандидата с четным младшим битом .)

Другое следствие:

  • Если результат операции с действительным числом представлен в формате с плавающей запятой, это результат с плавающей запятой. (Ошибка округления отсутствует.)

Теперь давайте рассмотрим выражения a / b и a2 / b2. Из-за смешанных типов первым шагом в каждом из них является преобразование a или a2 соответственно из целочисленного типа в double. Вопрос подсказывает нам, что целочисленный тип имеет 32 бита. Все 32-битные целые числа точно представимы в double (потому что double имеет 53-битные значения). Математическим результатом преобразования значения, конечно же, является само значение, поскольку преобразование предназначено для изменения типа, а не значения. Следовательно, результат преобразования a или a2 в double в точности равен a или a2, соответственно.

Далее идет деление, a / b или a2 / b2. Нам говорят, что a / b = a2 / b2. Это говорит нам о том, что результат действительного числа a / b равен результату действительного числа a2 / b2. Поскольку эти две операции имеют одинаковый результат вычисления действительного числа и используют одно и то же правило округления, их результаты с плавающей запятой одинаковы.

Обсуждение

Некоторые ограничения вышеперечисленного:

  • Если a или a2 может превышать 53 бита, оно может иметь значение, не представляемое в double. Тогда операция преобразования его в double должна будет округлить его. Округление может по-разному влиять на a и a2, и тогда коэффициенты a / b и a2 / b2 могут отличаться.
  • Некоторые языки программирования не являются строгими в отношении того, как выполняются операции с плавающей запятой, и они не соответствуют правилам IEEE-754. Я считаю, что вышеизложенное относится к Java, но могут быть проблемы в C или C ++.

Обратите внимание, что b и b2 могут быть настолько малы (включая ноль), что частное переполняется, и вычисляемый результат равен бесконечности. Тем не менее, тот факт, что a / b = a2 / b2 потребует, чтобы оба результата были бесконечными или нет - правило о том, что результаты с плавающей точкой равны действительным числам равны, все еще сохраняется.

Если a, a2, b и b2 являются нулями, то обе операции будут создавать NaN, но два NaN не будут сравниваться как равные.

Если a и a2 не равны нулю, а b и b2, то обе операции приведут к бесконечности. Знак будет XOR знаков числителя и делителя. Это означает, что a / b и a2 / b2 могут создавать разные бесконечности (одну положительную, одну отрицательную), даже если a = a2 и b = b2, потому что IEEE-754 имеет + + и -0 , которые сравнивают равные, но имеют разные знаки.

...