Как Java выполняет вычисления модуля с отрицательными числами?


96

Я неправильно делаю модуль? Потому что в Java -13 % 64предполагается оценивать, -13но я получаю 51.


102
@Dan Даже без статической основной пустоты ... Я вижу код.
Джорис Мейс,

22
Я получаю -13 и 64 == -13
Гродригес 02

7
Как это вы получаете 51 скорость, чем -13.
Raedwald

3
Вы вообще не занимаетесь модулем. В Java нет оператора по модулю. %является оператором остатка.
Маркиз Лорн,

3
Непонятный вопрос: Java 8 дает -13, как говорят некоторые. С какой версией Java вы предположительно это сделали?
Ян ankowski

Ответы:


105

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

Если вы хотите получить отрицательное число для отрицательных входов, вы можете использовать это:

int r = x % n;
if (r > 0 && x < 0)
{
    r -= n;
}

Точно так же, если вы использовали язык, который возвращает отрицательное число на отрицательном входе, и вы бы предпочли положительный:

int r = x % n;
if (r < 0)
{
    r += n;
}

3
Это не сработает, если n отрицательно. Если вы используете тот же пример из Java 7 Lang Spec (раздел 15.17.3): (-5)% (-3) = -2. Добавить -3 не получится. Вы должны добавить абсолютное значение n, если хотите быть уверенным, что значение положительное.
партлов

6
В Java отрицательный модуль ничего не меняет, если вы все равно используете Abs (), просто напишите r = x% abs (n). Мне не нравится оператор if, я бы лучше написал r = ((x% n) + n)% n. Что касается степени двойки по модулю (2,4,8,16 и т. Д.) И положительного ответа, рассмотрим двоичную маску r = x & 63.
Fabyen

3
В контексте Java (согласно тегу вопроса) этот ответ по сути «неправильный». Учитывая выражение x % y, А) , если xотрицательный остаток отрицательный, то есть x % y == -(-x % y). Б) знак yне действует, т.е.x % y == x % -y
Богемский

72

Поскольку "математически" оба верны:

-13 % 64 = -13 (on modulus 64)  
-13 % 64 = 51 (on modulus 64)

Разработчики языка Java должны были выбрать один из вариантов, и они выбрали:

знак результата равен знаку дивиденда.

Об этом говорится в спецификациях Java:

https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.3


8
Вопрос в том, «почему Java дает мне, -13 % 64 = 51когда я ожидал -13?».
Паскаль Куок

5
@pascal: java дает вам правильное математическое определение и способ его реализации, который не соответствует вашим ожиданиям.

9
Математически разумное поведение доступно в Java 8: Math.floorMod
Джесси Глик,

1
Что-то в их 15.17.3. Примеры Remainder Operator% неясны. int result = (-5) % 3;дает -2. int result = (-3) % 5;дает -3. В общем, int result = (-a) % b;дает правильный ответ, когда | -a | > б. Чтобы получить правильный результат, когда | -a | <b мы должны обернуть делитель. int result = ((-a) % b) + b;для отрицательного а или int result = (((-a) % b) + b) % b;для положительного или отрицательного а
Оз Эдри

@Caner Я этого не понял, как они могут быть одинаковыми?
Кишор Кумар Корада

20

Вы уверены, что работаете на Java? потому что Java дает -13% 64 = -13, как и ожидалось. Знак дивиденда!


15

Ваш результат неверен для Java. Пожалуйста, опишите контекст, как вы к этому пришли (ваша программа, реализация и версия Java).

От спецификации языка Java

15.17.3 Оставшийся оператор%
[...]
Операция остатка для операндов, которые являются целыми числами после двоичного числового продвижения (§5.6.2), производит такое значение результата, что (a / b) * b + (a% b) равно а.
15.17.2 Оператор отдела /
[...]
Целочисленное деление округляет до 0.

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


Что-то в их 15.17.3. Примеры Remainder Operator% неясны. int result = (-5) % 3;дает -2 int result = (-3) % 5;дает -3 В общем, int result = (-a) % b;дает правильный ответ, когда | -a | > b Чтобы получить правильный результат, когда | -a | <b мы должны обернуть делитель. int result = ((-a) % b) + b;для отрицательного a или int result = (((-a) % b) + b) % b;для положительного или отрицательного a.
Оз Эдри

1
Ваш комментарий довольно непонятен. Раздел определяет правильный результат, и примеры согласуются с этим определением. Для вашего примера (-3) % 5правильный результат согласно определению равен -3, и правильная реализация Java должна дать этот результат.
звездно-голубой

Думаю, я неправильно объяснил. Под «правильным ответом» при | -a | <b я имел в виду то, что для получения положительного результата мы должны «обернуть» данный результат из% b, добавив к нему b. В моем примере (-3)%5действительно дает -3, и если мы хотим получить положительный остаток, мы должны добавить к нему 5, и тогда результат будет2
Оз Эдри

6

ты можешь использовать

(x % n) - (x < 0 ? n : 0);

3
@ruslik Вы также можете сделать: ((x % k) + k) % k. (Хотя ваш, вероятно, более читабельный.)
Джон Курлак

2
@JohnKurlak Ваша версия работает так: 4% 3 = 1 OR 4% -3 = -2 OR -4% 3 = 2 OR -4% -3 = -1 но версия от ruslik работает так: 4% 3 = 1 ИЛИ 4% -3 = 1 ИЛИ -4% 3 = -4 ИЛИ -4% -3 = 2
Джошуа

1
@Joschua Спасибо, что указали на это. Мой код полезен, когда вы хотите, чтобы результат модуля находился в диапазоне [0, sign(divisor) * divisor)вместо [0, sign(dividend) * divisor).
John Kurlak

3

Ваш ответ находится в Википедии: операция по модулю

В нем говорится, что в Java знак операции по модулю такой же, как у делимого. и поскольку мы говорим об остальной части операции деления, это нормально, что она возвращает -13 в вашем случае, поскольку -13/64 = 0. -13-0 = -13.

РЕДАКТИРОВАТЬ: Извините, неправильно понял ваш вопрос ... Вы правы, java должна дать -13. Можете ли вы предоставить больше окружающего кода?


2

Арифметика по модулю с отрицательными операндами определяется разработчиком языка, который может оставить это языковой реализации, которая может передать определение архитектуре ЦП.

Мне не удалось найти определение языка Java.
Спасибо, Иштар, Спецификация языка Java для оператора остатка% говорит, что знак результата такой же, как знак числителя.


1

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

int k = -13;
int modbase = 64;

while (k < 0) {
    k += modbase;
}

int result = k % modbase;

Результат все равно будет в том же классе эквивалентности.


1

x = x + m = x - mпо модулю m.
так -13 = -13 + 64по модулю 64 и -13 = 51по модулю 64.
Допустим Z = X * d + r, если 0 < r < Xтогда делением Z/Xназовем rостаток.
Z % Xвозвращает остаток Z/X.


1

Функция mod определяется как величина, на которую число превышает наибольшее целое кратное делителя, не превышающее это число. Итак, в вашем случае

-13 % 64

наибольшее целое число, кратное 64, которое не превышает -13, равно -64. Теперь, когда вы вычитаете -13 из -64, получается 51-13 - (-64) = -13 + 64 = 51


0

В моей версии Java JDK 1.8.0_05 -13% 64 = -13

вы можете попробовать -13- (int (-13/64)), другими словами, деление приведено к целому числу, чтобы избавиться от дробной части, а затем вычесть ее из числителя. Итак, numerator- (int (числитель / знаменатель)) должен дать правильный остаток и подпись


0

В последних версиях Java вы получаете -13%64 = -13. Ответ всегда будет иметь знак числителя.


В какой версии было внесено это изменение?
NightShadeQueen

В java 7 явно упоминается, что у мода будет знак числителя :)
vsn harish rayasam

@NightShadeQueen Это никогда не менялось.
Маркиз Лорн

0

Согласно разделу 15.17.3 JLS, «операция с остатком для операндов, которые являются целыми числами после двоичного числового продвижения, выдает такое значение результата, что (a / b) * b + (a% b) равно a. Это тождество сохраняется даже в особом случае, когда дивиденд - это отрицательное целое число максимально возможной величины для данного типа, а делитель равен -1 (остаток равен 0) ».

Надеюсь, это поможет.


-1

Я не думаю, что Java в этом случае возвращает 51. Я запускаю Java 8 на Mac и получаю:

-13 % 64 = -13

Программа:

public class Test {
    public static void main(String[] args) {
        int i = -13;
        int j = 64;
        System.out.println(i % j);
    }
}

5
@XaverKapeller, нет! Многие люди указали, что с математической точки зрения -13 и 51 верны. В Java ожидаемым ответом является -13, и это то, что я получил, поэтому я не знаю, как отправитель получил 51, это загадка. Подробности режима о контексте могут помочь правильно ответить на этот вопрос.
Fabyen

@Xaver Kapeller: Почему 51 и -13 могут быть правильными? Java вернет только одно значение ..
ceprateek

@XaverKapeller Как может ответ, документирующий, что на самом деле делает Java, ошибочен?
Маркиз Лорн

@EJP Я думаю, что 3 года назад, когда я писал это, я был достаточно глуп, чтобы ценить математическую точность больше, чем простая реальность того, как Java справляется с этим. Спасибо, что напомнили мне удалить мой глупый комментарий: D
Ксавер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.