Простое деление в Java - это ошибка или фича? - PullRequest
17 голосов
/ 26 мая 2010

Я пытаюсь выполнить простой расчет в приложении Java:

System.out.println("b=" + (1 - 7 / 10));

Очевидно, я ожидаю, что результат будет b=0.3, но вместо этого я получаю b=1.

Что ?! Почему это происходит?

Если я напишу:

System.out.println("b=" + (1 - 0.7));

Я получаю правильный результат, который b=0.3.

Что здесь не так?

Ответы [ 5 ]

59 голосов
/ 26 мая 2010

Вы используете целочисленное деление.

Попробуйте 7.0/10.

24 голосов
/ 26 мая 2010

Вы использовали целые числа в выражении 7/10, а целое число 7, деленное на целое число 10, равно нулю.

То, что вы ожидаете, это деление с плавающей запятой. Любое из следующего оценило бы, как вы ожидали:

7.0 / 10
7 / 10.0
7.0 / 10.0
7 / (double) 10
9 голосов
/ 26 мая 2010

Пожалуйста, не принимайте это как ответ на вопрос. Это не так, но совет, связанный с использованием различий между int и float. Я бы поместил это под комментарием, за исключением того, что поле ответа позволяет мне форматировать этот комментарий.

Эта функция использовалась во всех уважаемых языках программирования со времен Фортрана (или ранее) - я должен признаться, что когда-то был программистом перфокарт на Фортране и Коболе.

В качестве примера, целочисленное деление 10/3 дает целочисленное значение 3, поскольку целое число не имеет возможности хранить дробный остаток .3333 ...

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

Допустим, мы хотим напечатать массив из 1000 строк, но мы хотим вставить разрыв строки после каждой 15-й строки, чтобы вставить несколько симпатичных символов в конце строки и в начале следующей строки. Мы используем это, учитывая, что целое число k - позиция строки в этом массиве.

int(k/15)*15 == k

верно только тогда, когда k делится на 15, что происходит с частотой каждой 15-й ячейки. Что сродни тому, что сказал мой друг о том, что мертвые часы его деда точны два раза в день.

int(1/15) = 0 -> int(1/15)*15 = 0
int(2/15) = 0 -> int(2/15)*15 = 0
...
int(14/15) = 0 -> int(14/15)*15 = 0
int(15/15) = 1 -> int(15/15)*15 = 15

int(16/15) = 1 -> int(16/15)*15 = 15
int(17/15) = 1 -> int(17/15)*15 = 15
...
int(29/15) = 1 -> int(29/15)*15 = 15
int(30/15) = 2 -> int(30/15)*15 = 30

Следовательно, цикл,

leftPrettyfy();
for(int k=0; k<sa.length; k++){
  print(sa[k]);
  int z = k + 1;
  if ((z/15)*15 == z){
    rightPrettyfy();
    leftPrettyfy();
  }
}

При причудливом изменении k в цикле мы можем напечатать треугольную распечатку

1
2  3
4  5  6
7  8  9  10
11 12 13 14 15

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

1 голос
/ 26 мая 2010

Я нахожу буквенные идентификаторы более читабельными и более показательными для разбираемого типа:

1 - 7f / 10
1 - 7 / 10f

или

1 - 7d / 10
1 - 7 / 10d
0 голосов
/ 12 января 2017

В моем случае я делал это:

double a = (double) (MAX_BANDWIDTH_SHARED_MB/(qCount+1));

Вместо «правильного»:

double a = (double)MAX_BANDWIDTH_SHARED_MB/(qCount+1);

Обратите внимание на скобки!

...