Я писал этот код:
public static void main(String[] args) {
double g = 1 / 3;
System.out.printf("%.2f", g);
}
Результат - 0. Почему и как решить эту проблему?
Ответы:
Два операнда (1 и 3) являются целыми числами, поэтому используется целочисленная арифметика (здесь деление). Объявление переменной результата как double просто вызывает неявное преобразование после деления .
Целочисленное деление, конечно, возвращает истинный результат деления с округлением до нуля. Таким образом, результат 0.333...
здесь округляется до 0. (Обратите внимание, что процессор на самом деле не округляет, но вы можете думать об этом так же.)
Также обратите внимание, что если оба операнда (числа) заданы как числа с плавающей запятой; 3.0 и 1.0, или даже только первая , тогда используется арифметика с плавающей запятой, что дает вам 0.333...
.
DOWN
идет в сторону нуля. Округление FLOOR
в сторону отрицательной бесконечности.
1/3
использует целочисленное деление, поскольку обе стороны являются целыми числами.
Вам нужно, чтобы хотя бы один из них был float
или double
.
Если вы вводите значения в исходный код, как ваш вопрос, вы можете сделать это 1.0/3
; 1.0
является двойной.
Если вы получаете значения из других источников, вы можете использовать их (double)
для int
преобразования в double
.
int x = ...;
int y = ...;
double value = ((double) x) / y;
вы должны использовать
double g=1.0/3;
или
double g=1/3.0;
Целочисленное деление возвращает целое число.
Потому что вы делаете целочисленное деление.
Как говорит @Noldorin, если оба оператора являются целыми числами, используется целочисленное деление.
Результат 0,33333333 не может быть представлен как целое число, поэтому результату присваивается только целая часть (0).
Если какой-либо из операторов - это double
/ float
, то будет выполняться арифметика с плавающей запятой. Но у вас будет та же проблема, если вы это сделаете:
int n = 1.0 / 3.0;
Потому что он обрабатывает 1 и 3 как целые числа, поэтому результат округляется до 0, так что это целое число.
Чтобы получить результат, который вы ищете, явно сообщите java, что числа удваиваются, например:
double g = 1.0/3.0;
Преобразование в JAVA довольно простое, но требует некоторого понимания. Как объясняется в JLS для целочисленных операций :
Если у целочисленного оператора, отличного от оператора сдвига, есть хотя бы один операнд типа long, тогда операция выполняется с 64-битной точностью, а результат числового оператора имеет тип long. Если другой операнд не является длинным, он сначала расширяется (§5.1.5), чтобы набрать длинный путем числового продвижения (§5.6).
И пример - всегда лучший способ перевести JLS;)
int + long -> long
int(1) + long(2) + int(3) -> long(1+2) + long(3)
В противном случае операция выполняется с 32-битной точностью, а результат числового оператора имеет тип int. Если любой из операндов не является int, он сначала расширяется до типа int путем числового продвижения.
short + int -> int + int -> int
Небольшой пример с использованием Eclipse, показывающий, что даже сложение двух short
s не так просто:
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 и 3 являются целочисленными константами, поэтому Java выполняет целочисленное деление, результатом которого является 0. Если вы хотите написать двойные константы, вы должны написать 1.0
и 3.0
.
Самое простое решение - просто сделать это
double g = ((double) 1 / 3);
Что это значит, поскольку вы не вводили 1.0 / 3.0, это позволяет вам вручную преобразовать его в тип данных double, поскольку Java предполагала, что это целочисленное деление, и будет делать это, даже если это означает сужение преобразования. Это то, что называется оператором приведения.
Я сделал это.
double g = 1.0/3.0;
System.out.printf("%gf", g);
Используйте .0 при выполнении двойных вычислений, иначе Java будет предполагать, что вы используете целые числа. Если в вычислении используется любое количество двойных значений, то на выходе будет двойное значение. Если все целые числа, то на выходе будет целое число.
(1/3) означает целочисленное деление, поэтому вы не можете получить десятичное значение из этого деления. Для решения этой проблемы используйте:
public static void main(String[] args) {
double g = 1.0 / 3;
System.out.printf("%.2f", g);
}
public static void main(String[] args) {
double g = 1 / 3;
System.out.printf("%.2f", g);
}
Поскольку и 1, и 3 являются целыми числами, результат не округляется, а усекается. Таким образом, вы игнорируете дроби и берете только целые.
Чтобы избежать этого, используйте хотя бы одно из ваших чисел 1 или 3 в десятичной форме 1.0 и / или 3.0.
Попробуйте это:
public static void main(String[] args) {
double a = 1.0;
double b = 3.0;
double g = a / b;
System.out.printf(""+ g);
}
Сделайте «двойной г = 1.0 / 3.0;» вместо.
Многие другие не смогли указать на настоящую проблему:
Операция только с целыми числами переводит результат операции в целое число.
Это обязательно означает, что результаты с плавающей запятой, которые могут отображаться как целые числа, будут усечены (отсечена десятичная часть).
Что такое приведение типов / преобразование типов, спросите вы?
Это зависит от реализации языка, но Википедия имеет довольно исчерпывающий обзор, и в ней также говорится о принуждении , что является ключевой информацией при ответе на ваш вопрос.
1/2
, в целевом языке (java). Вы просто вызываете целочисленное деление, которое приводит к целочисленному результату. Приведение типа происходит только из-за повышающего преобразования из int
в double
во время присвоения.
0.5
. Проще говоря, в Java 1/2
это целочисленное деление, которое дает нулевое целое число. Вы можете присвоить дублю ноль, он все равно будет нулем, хотя и 0.0
двойным.
int i = .99999999
устанавливает int в 0. Точнее говоря, он берет целую часть и отбрасывает остальное.