Деление Int: Почему результат 1/3 == 0? - PullRequest
87 голосов
/ 14 января 2011

Я писал этот код:

public static void main(String[] args) {
    double g = 1 / 3;
    System.out.printf("%.2f", g);
}

Результат равен 0. Почему и как мне решить эту проблему?

Ответы [ 15 ]

124 голосов
/ 14 января 2011

Два операнда (1 и 3) являются целыми числами, поэтому используется целочисленная арифметика (здесь деление). Объявление переменной результата как double просто приводит к неявному преобразованию после деления .

Целочисленное деление, конечно, возвращает истинный результат деления, округленный до нуля. Таким образом, результат 0.333... здесь округляется до 0. (Обратите внимание, что процессор фактически не выполняет никакого округления, но вы все равно можете думать об этом.)

Также обратите внимание, что если , то оба операнда (числа) задаются как числа с плавающей запятой; 3.0 и 1.0, или даже просто сначала , затем используется арифметика с плавающей точкой, что дает вам 0.333....

20 голосов
/ 14 января 2011

1/3 использует целочисленное деление, поскольку обе стороны являются целыми числами.

Вам нужно хотя бы одно из них, чтобы оно было float или double.

Если вы вводите значенияв исходном коде, как ваш вопрос, вы можете сделать 1.0/3;1.0 - это двойное число.

Если вы получаете значения из других источников, вы можете использовать (double), чтобы превратить int в double.

int x = ...;
int y = ...;
double value = ((double) x) / y;
10 голосов
/ 14 января 2011

Явно приведите его как double

double g = 1.0/3.0

Это происходит потому, что Java использует целочисленное деление для 1 и 3, поскольку вы ввели их как целочисленные константы.

2 голосов
/ 14 января 2011

Вы должны использовать

double g=1.0/3;

или

double g=1/3.0;

Целочисленное деление возвращает целое число.

2 голосов
/ 14 января 2011

Потому что вы делаете целочисленное деление.

Как говорит @Noldorin, если оба оператора являются целыми числами, то используется целочисленное деление.

Результат 0.33333333 не может быть представлен как целое число, поэтому результату присваивается только целая часть (0).

Если какой-либо из операторов является double / float, то будет иметь место арифметика с плавающей запятой. Но у вас будет такая же проблема, если вы сделаете это:

int n = 1.0 / 3.0;
1 голос
/ 02 февраля 2019

Самое простое решение - просто сделать это

double g = ((double) 1 / 3);

Что это делает, поскольку вы не ввели 1.0 / 3.0, это позволяет вам вручную преобразовать его в тип данных double, поскольку Java предполагала, что это целочисленное деление, и это будет сделано, даже если это означает сужение преобразования. Это то, что называется оператором приведения.

1 голос
/ 24 января 2017

Преобразование в JAVA довольно просто, но требует некоторого понимания.Как объясняется в JLS для целочисленных операций :

Если у целочисленного оператора, отличного от оператора сдвига, есть хотя бы один операнд типа long, то операция выполняется с использованием 64-битная точность, и результат числового оператора имеет тип long.Если другой операнд не длинный, он сначала расширяется (§5.1.5), чтобы печатать long с помощью числового преобразования (§5.6).

И пример всегда является лучшим способом перевода JLS;)

int + long -> long
int(1) + long(2) + int(3) -> long(1+2) + long(3)

В противном случае операция выполняется с 32-битной точностью, ирезультат числового оператора имеет тип int.Если любой из операндов не является целым, он сначала расширяется до типа int с помощью числового продвижения.

short + int -> int + int -> int

Небольшой пример использования Eclipse, чтобы показать, что даже добавление двух short не будет таким простым:

short s = 1;
s = s + s; <- Compiling error

//possible loss of precision
//  required: short
//  found:    int

Это потребует приведения свозможная потеря точности.

То же самое верно для операторов с плавающей запятой

Если хотя бы один из операндов числового оператора имеет типdouble, тогда операция выполняется с использованием 64-битной арифметики с плавающей точкой, а результатом числового оператора является значение типа double.Если другой операнд не является двойным, он сначала расширяется (§5.1.5), чтобы набрать double путем числового преобразования (§5.6).

Таким образом, продвижение выполняется с плавающей точкой в ​​двойное число.

И смешивание целых и плавающих значений приводит к плавающим значениям, как сказано

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

Это верно для бинарных операторов, но не для «операторов присваивания», таких как +=

Достаточно простого рабочего примера, чтобы доказать это

int i = 1;
i += 1.5f;

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

i = (int) i + 1.5f
i = (int) 2.5f
i = 2
1 голос
/ 14 января 2011

Сделайте 1, будет использоваться деление поплавка и поплавка

public static void main(String d[]){
    double g=1f/3;
    System.out.printf("%.2f",g);
}
1 голос
/ 14 января 2011

Поскольку он обрабатывает 1 и 3 как целые числа, следовательно, округляет результат до 0, так что это целое число.

Чтобы получить результат, который вы ищете, явным образом сообщите java, что числа являются двойными, например:

double g = 1.0/3.0;
1 голос
/ 14 января 2011

1 и 3 являются целочисленными константами, и поэтому Java выполняет целочисленное деление, результатом которого является 0. Если вы хотите записать двойные константы, вы должны написать 1.0 и 3.0.

...