2013-03-12 1 views
1

Может ли result быть ложным, потому что 4/2.0 может вернуть что-то вроде 1.99999999? В более общем плане, чем название:Может ли ошибка с плавающей запятой вызывать 'a/(double) b> = a/b' для отказа?

int a = // any valid int 
int b = // any valid int 
boolean result = (a/(double)b) >= a/b; 

Если это возможно, может кто-нибудь привести пример a и b? Если это невозможно, существует ли какая-либо спецификация java или с плавающей запятой, которая доказывает это?

Я написал эту логику несколько минут назад и внезапно волновался об этом. Я не смог его сломать, но мне интересно, гарантировано ли это во всех JVM.

ответ

5

Если a и b являются положительными int значениями, то a/(double)b >= a/b.

Я использую следующие помещения, наряду с понимаемыми семантиками, например, что значение a/bint будет преобразованы в double для сравнения с другим операндом >=.

помещений:

  • Диапазон int является [-2147483648, 2147483648).
  • double - 64-битный двоичный код IEEE 754.
  • Режим округления округлен до ближайшего.
  • Все операции с плавающей запятой, в частности деление, соответствуют IEEE 754.
  • Целое число a/b усекает к нулю.

Обозначение:

  • является математическим значением a.
  • b - математическое значение b.
  • Математические выражения, такие как a/ b, являются точными, в отличие от вычисленных выражений, таких как a/b.
  • Позвольте L быть значением, произведенным для a/(double)b.
  • Позвольте R быть значением, произведенным для a/b.

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

  • Все int значения представимы в double, поэтому IEEE 754 требует, чтобы преобразования int в double быть точным.
  • Поэтому (double) a и (double) bпроизводят и б точно, и a/(double)b производит с/ б правильно округленное до ближайшего double.
  • Поскольку R является / б усекается к нулю, и / б положительна, R является пол (/ б).
  • Наибольший a/ b может составлять 2,147,483,647/1 = 2,147,483,647. Каждое целое число при этой величине и ниже точно представляется в виде double.
  • л является ближайшим double/ б. Если L уменьшается округлением, оно уменьшается до следующего нижнего double. Так как все целые числа в этих величинах представимы, пол (/ б) представим, поэтому л, по крайней мере пол (/ б).
  • Поэтому LR.
  • Превращение R к double является точным, так что сравнение л к R с >= производит тот же результат, как математическое LR.
+0

Спасибо за отличный ответ! –

0

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

Отрицательные номера могут привести к отказу от сравнения. Обратите внимание, что -1/2 = 0, а -1.0/2.0 = -0.5.

+1

+1 для примера. Однако «деление с плавающей запятой точное» нуждается в некоторой квалификации; что именно вы имеете в виду? –

+0

Также потому, что это двоичные цифры, нет? '4/2.0' является' 4 * 2^(- 1) ', который, IIRC, является тем, как хранятся поплавки. – wchargin

+0

@OliCharlesworth: Разделение двух чисел с плавающей запятой всегда возвращает самое близкое число с плавающей запятой к частному. – tmyklebu

2

Для отрицательных чисел, он не при а = -10, б = 3.

Для положительных входов только, я думаю, что вы в безопасности.

Пусть x - действительный результат числа деления a на b.

Сначала рассмотрим случай, когда x представляется в виде int. Он также представляется как двойной, и оба вычисления возвращают x.

Теперь предположим, что x не является int. Вопрос в том, может ли абсолютная величина разности ошибок округления между x и a/(double b) когда-либо превышать ошибку усечения для a/b. Это не может.

Ошибка усечения t = x - a/b должна быть не менее 1/b. x не может быть больше Integer.MAX_VALUE/b, поэтому t/x не менее 1/Integer.MAX_VALUE. Это намного больше, чем максимальная ошибка округления при правильно округленном двойном вычислении.

Смежные вопросы