Являются ли арифметические операции с двойными переменными целыми значениями точными?

Скажем, у меня есть два целочисленных значения, хранящихся в переменных double, e. г:.

double x = 100.0;
double y = 7.0;

Можно ли смело предположить, что любая арифметическая операция над этими двумя двойными переменными, которая давала бы целочисленный результат, вернет точное целочисленное значение (как double)? То есть, будет, например, все:

x + y = 107.0
x - y = 93.0
x * y = 700.0

вернет точные целочисленные значения или будут проблемы с точностью? Как x*y, являющийся 699.99995 или так?

Общий вопрос: Верно ли, что любая арифметическая операция над двумя двойными переменными, содержащая целочисленные значения, которые приведут к целочисленному результату, вернет точное целочисленное значение (как двойное)?

Я спрашиваю об этом в контексте Java, но я предполагаю, что он аналогичен и на других языках.

Ответы

Ответ 1

Пока целочисленный результат вашей операции может быть точно представлен как двойной, вы получите точный результат, но как только целочисленный результат превысит количество бит, доступных в мантиссе (т.е. 52 + 1 = 53 бит), он будет округлен.

Ответ 3

Нет, если результирующее число имеет слишком много цифр, чтобы соответствовать double. Например, 1234567890.0 * 1234567890.0 дает 1,52415787501905E+18, а не 1524157875019052100. Я не знаю, будет ли всегда быть точным, если результат будет соответствовать, но @Sven Marnach ответил на это. Я предполагаю, что усеченное число будет отключено точным целым числом, как говорит @Douglas Leeder, потому что мантисса, сдвинутая экспонентом (которая больше, чем число цифр в мантиссе), станет целым числом.

Ответ 4

Отличное обсуждение, все.

Ваш вопрос

Верно ли, что любая арифметика операция по двум двойным переменным содержащие целочисленные значения, которые выведите целочисленный результат точное целочисленное значение (как двойное)?

Я выбрал пограничный случай, где два числа были ровно 53 бит. 54-битная сумма превышала емкость двойника, и она не возвращала точный целочисленный результат. Как и ожидалось, бит младшего разряда был усечен, и у вас был странный, но ожидаемый результат.

Нечетное число плюс четное число не дает нечетной суммы (как скажет вам математика); Java сообщает четное число (как сообщит вам стандарт IEEE).

Попробуйте этот образец:

private static void doubleCalc() {
  double x = 4503599627370497.0d; // binary 10000000000000000000000000000000000000000000000000001
  double y = 4503599627370496.0d; // binary 10000000000000000000000000000000000000000000000000000

  double sum = x + y;
  System.out.println("sum=" + sum + "; should be 9007199254740993.0d");
}

Он распечатает:

sum=9.007199254740992E15; should be 9007199254740993.0d

Таким образом, этот тщательно подобранный контрпример будет отвечать "нет" на ваш тщательно сформулированный вопрос.

Ответ 5

Все значения int могут быть точно представлены значениями double, а операции +, *, - работают одинаково здесь (если вы не превысите диапазон int). Операторы / и % работают по-разному.

Поскольку double имеет только 52 бит мантиссы, вы не можете точно представлять все значения long.

Ответ 6

Пока цифры не слишком далеко друг от друга (например, 2 ^ 1024 и 0,005), результаты должны быть точными. Номера с плавающей запятой с двойной точностью работают следующим образом: 1 бит для знака, 11 для экспоненты и 52 бит для мантиссы. Конечное число равно ((-1) * (знак)) (1.mantissa < (экспонента - 1 < 10)), поэтому, когда добавление производится между двумя числами, это происходит:

x = number with greatest exponent
y = number with smallest exponent

(in case of same sign)
z.mantissa = x.mantissa + (y.mantissa >> (x.exponent - y.exponent) )
sign = either_one.sign

(in case of opposite sign)
z.mantissa = x.mantissa - (y.mantissa >> (x.exponent - y.exponent) )
sign = x.sign

для умножения/деления это немного проще:

z.exponent = x.exponent + y.exponent
z.mantissa = 1.(x.mantissa) (operand) (y.mantissa)
z.sign = x.sign != y.sign
while (z.mantissa is not in format 1.x)
   z.mantissa << 1 (division)
   z.exponent--
   z.mantissa >> 1 (multiplication)
   z.exponent++

Итак, что происходит, если экспоненты находятся слишком далеко друг от друга, будет потеря данных при сдвиге, то есть точность для double (с плавающей запятой в целом) не на 100% точнее (тем более, что некоторые числа превращаются в периодические опустошает). Однако для идеальных целых чисел (и результатов) это должно быть хорошо, если число до 52 бит (размер мантиссы), поскольку оно может быть смещено на целое число с помощью процессора (например, 1.111 < 3 1111).

Ответ 7

В связанном вопросе мне было указано, что двойной имеет около 15 цифр точности, в то время как он может содержать до 10^(300+) большие числа. Поэтому я предполагаю, что если вы используете меньший int, это не должно быть большой проблемой.

Это немного сказано в учебниках оракула:

double: двойной тип данных - это 64-разрядная 64-битная плавающая точка IEEE 754 с двойной точностью. Его диапазон значений выходит за рамки этого обсуждения, но указан в разделе 4.2.3 Спецификации языка Java. Для десятичных значений этот тип данных обычно является выбором по умолчанию. Как уже упоминалось выше, этот тип данных никогда не должен использоваться для точных значений, таких как валюта.

Для дальнейшего использования здесь ссылка на раздел 4.2.3, упомянутый выше.