Como o java faz cálculos de módulo com números negativos?


92

Estou fazendo o módulo errado? Porque em Java -13 % 64é suposto avaliar, -13mas eu consigo 51.


102
@Dan Mesmo sem um vazio principal estático ... vejo o código.
Joris Meys

22
Recebo -13 e 64 == -13
Grodriguez

7
Como é que você está obtendo taxa de 51 a -13.
Raedwald

3
Você não está fazendo módulo de forma alguma. Não há operador de módulo em Java. %é um operador de resto.
Marquês de Lorne

3
Pergunta confusa: Java 8 dá -13, como algumas pessoas dizem. Com qual versão do Java você supostamente conseguiu isso?
Jan Żankowski

Respostas:


103

Ambas as definições de módulo de números negativos estão em uso - algumas linguagens usam uma definição e outras a outra.

Se você deseja obter um número negativo para entradas negativas, você pode usar isto:

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

Da mesma forma, se você estiver usando um idioma que retorna um número negativo em uma entrada negativa e preferir o positivo:

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

3
Isso não funciona bem se n for negativo. Se você usar o mesmo exemplo do Java 7 Lang Spec (Seção 15.17.3): (-5)% (-3) = -2. Adicionar -3 não funcionará. Você deve adicionar o valor absoluto de n se quiser ter certeza de que o valor é positivo.
partlov 02 de

6
Em Java, o módulo negativo não muda nada, se você usar um Abs () de qualquer maneira, basta escrever r = x% abs (n). Não gosto da declaração if, prefiro escrever r = ((x% n) + n)% n. Com relação à potência de 2 módulos (2,4,8,16, etc.) e resposta positiva, considere a máscara binária r = x & 63.
Fabyen

3
No contexto do Java (de acordo com a tag de pergunta), essa resposta é essencialmente "errada". Dada a expressão x % y, A) se xfor negativo, o resto é negativo, ou seja x % y == -(-x % y). B) o sinal de ynão tem efeito, ou sejax % y == x % -y
Boêmio

71

Uma vez que "matematicamente" ambos estão corretos:

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

Uma das opções teve que ser escolhida pelos desenvolvedores da linguagem Java e eles escolheram:

o sinal do resultado é igual ao sinal do dividendo.

Diz nas especificações do Java:

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


8
A questão é "por que o Java me deu -13 % 64 = 51quando eu estava esperando -13?".
Pascal Cuoq

5
@pascal: java dá a você a definição correta em matemática e a maneira como foi implementado para fazer isso não é o que você espera dele.

9
O comportamento matematicamente lógico
Jesse Glick

1
Algo em seu 15.17.3. Os exemplos de % do operador restante não são claros. int result = (-5) % 3;dá -2. int result = (-3) % 5;dá -3. Em geral, int result = (-a) % b;dá a resposta certa quando | -a | > b. Para obter o resultado adequado quando | -a | <b devemos envolver o divisor. int result = ((-a) % b) + b;para a negativo ou int result = (((-a) % b) + b) % b;para a positivo ou negativo
Oz Edri

@Caner Eu não entendi isso, como podem ser os dois?
Kishore Kumar Korada

20

Tem certeza de que está trabalhando em Java? porque o Java dá -13% 64 = -13 conforme o esperado. O sinal do dividendo!


15

Seu resultado está errado para Java. Forneça algum contexto de como você chegou a isso (seu programa, implementação e versão do Java).

Da especificação da linguagem Java

15.17.3 Operador restante%
[...]
A operação restante para operandos que são inteiros após a promoção numérica binária (§5.6.2) produz um valor de resultado tal que (a / b) * b + (a% b) é igual a uma.
15.17.2 Operador de divisão / divisão
[...]
inteiro rodadas para 0.

Como / é arredondado para zero (resultando em zero), o resultado de% deve ser negativo neste caso.


Algo em seu 15.17.3. Os exemplos de % do operador restante não são claros. int result = (-5) % 3;dá -2 int result = (-3) % 5;dá -3 Em geral, int result = (-a) % b;dá a resposta certa quando | -a | > b Para obter o resultado adequado quando | -a | <b devemos envolver o divisor. int result = ((-a) % b) + b;para a negativo ou int result = (((-a) % b) + b) % b;para a positivo ou negativo.
Oz Edri

1
Seu comentário não está claro. A seção define o resultado correto e os exemplos concordam com essa definição. Para seu exemplo, (-3) % 5o resultado correto de acordo com a definição é -3, e uma implementação correta de Java deve produzir esse resultado.
starblue

Acho que não me expliquei corretamente. O que quero dizer com "a resposta certa" quando | -a | <b é que, para obter um resultado positivo, devemos "quebrar" o resultado dado de a% b adicionando b a ele. No meu exemplo, (-3)%5realmente dá -3, e se quisermos o resto positivo, devemos adicionar 5 a ele, e então o resultado será2
Oz Edri

6

você pode usar

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

3
@ruslik Você também pode fazer: ((x % k) + k) % k. (Embora o seu seja provavelmente mais legível.)
John Kurlak

2
@JohnKurlak Sua versão funciona assim: 4% 3 = 1 OR 4% -3 = -2 OR -4% 3 = 2 OR -4% -3 = -1 mas o de ruslik funciona assim: 4% 3 = 1 OR 4% -3 = 1 OR -4% 3 = -4 OR -4% -3 = 2
Joschua

1
@Joschua Obrigado por apontar isso. Meu código é útil quando você deseja que o resultado do módulo esteja na faixa de em [0, sign(divisor) * divisor)vez de [0, sign(dividend) * divisor).
John Kurlak de

3

Sua resposta está na wikipedia: modulo operation

Ele diz que em Java o sinal sobre a operação do módulo é o mesmo que o do dividendo. e como estamos falando sobre o resto da operação de divisão está tudo bem, ele retorna -13 no seu caso, uma vez que -13/64 = 0. -13-0 = -13.

EDIT: Desculpe, não entendi sua pergunta ... Você está certo, java deve dar -13. Você pode fornecer mais código circundante?


2

O módulo aritmético com operandos negativos é definido pelo designer da linguagem, que pode deixar para a implementação da linguagem, que pode adiar a definição para a arquitetura da CPU.

Não consegui encontrar uma definição de linguagem Java.
Obrigado Ishtar, Java Language Specification for the Remainder Operator% diz que o sinal do resultado é o mesmo que o sinal do numerador.


1

Para superar isso, você pode adicionar 64(ou qualquer que seja a sua base de módulo) ao valor negativo até que seja positivo

int k = -13;
int modbase = 64;

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

int result = k % modbase;

O resultado ainda estará na mesma classe de equivalência.


1

x = x + m = x - mem módulo m.
então -13 = -13 + 64em módulo 64 e -13 = 51em módulo 64.
suponha Z = X * d + r, se 0 < r < Xentão na divisão Z/Xchamamos ro resto.
Z % Xretorna o restante de Z/X.


1

A função mod é definida como o valor pelo qual um número excede o maior múltiplo inteiro do divisor que não é maior que esse número. Então, no seu caso de

-13 % 64

o maior múltiplo inteiro de 64 que não excede -13 é -64. Agora, quando você subtrai -13 de -64, é igual a 51-13 - (-64) = -13 + 64 = 51


0

Na minha versão do Java JDK 1.8.0_05 -13% 64 = -13

você poderia tentar -13- (int (-13/64)) em outras palavras, fazer a divisão do cast para um inteiro para se livrar da parte da fração e depois subtrair do numerador Assim, numerador- (int (numerador / denominador)) deve fornecer o correto resto e sinal



0

De acordo com a seção 15.17.3 do JLS, "A operação restante para operandos que são inteiros após a promoção numérica binária produz um valor de resultado tal que (a / b) * b + (a% b) é igual a a. Essa identidade é válida mesmo no caso especial em que o dividendo é o inteiro negativo de maior magnitude possível para o seu tipo e o divisor é -1 (o resto é 0). "

Espero que ajude.


-1

Não acho que Java retorne 51 neste caso. Estou executando o Java 8 em um Mac e recebo:

-13 % 64 = -13

Programa:

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

5
@XaverKapeller, não! Muitas pessoas apontaram que matematicamente falando -13 e 51 estão corretos. Em Java, -13 é a resposta esperada e é o que eu também tenho, então não sei como o remetente conseguiu 51, é um mistério. Os detalhes do modo sobre o contexto podem ajudar a responder corretamente a esta pergunta.
Fabyen de

@Xaver Kapeller: Como os valores 51 e -13 podem estar corretos? Java retornaria apenas um valor ..
ceprateek

@XaverKapeller Como uma resposta que documenta o que o Java realmente faz pode estar errada?
Marquês de Lorne

@EJP Acho que há 3 anos, quando escrevi isso, fui burro o suficiente para valorizar a precisão matemática mais do que a simples realidade de como o java lida com isso. Obrigado por me lembrar de remover meu comentário estúpido: D
Xaver Kapeller
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.