¿Cómo hace Java los cálculos de módulo con números negativos?

93

¿Estoy haciendo mal el módulo? Porque en Java -13 % 64se supone que debe evaluarse, -13pero obtengo 51.

Jakir00
fuente
102
@Dan Incluso sin un vacío principal estático ... veo el código.
Joris Meys
22
Obtengo -13 y 64 == -13
Grodriguez
7
¿Cómo es que está obteniendo 51 ratehr que -13?
Raedwald
3
No estás haciendo módulo en absoluto. No hay un operador de módulo en Java. %es un operador de resto.
Marqués de Lorne
3
Pregunta confusa: Java 8 da -13, como dicen otras personas. ¿Con qué versión de Java supuestamente obtuviste eso?
Jan Żankowski

Respuestas:

104

Se utilizan ambas definiciones de módulo de números negativos: algunos lenguajes utilizan una definición y otros la otra.

Si desea obtener un número negativo para las entradas negativas, puede usar esto:

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

Del mismo modo, si estuviera utilizando un idioma que devuelve un número negativo en una entrada negativa y preferiría positivo:

int r = x % n;
if (r < 0)
{
    r += n;
}
Mark Byers
fuente
3
Esto no funciona bien si n es negativo. Si usa el mismo ejemplo de Java 7 Lang Spec (Sección 15.17.3): (-5)% (-3) = -2. Agregar -3 no funcionará. Debe agregar el valor absoluto de n si desea asegurarse de que el valor sea positivo.
partlov
6
En Java el módulo negativo no cambia nada, si usa un Abs () de todos modos, simplemente escriba r = x% abs (n). No me gusta la declaración if, prefiero escribir r = ((x% n) + n)% n. Con respecto a la potencia de 2 módulo (2,4,8,16, etc.) y respuesta positiva, considere la máscara binaria r = x & 63.
Fabyen
3
En el contexto de Java (según la etiqueta de pregunta), esta respuesta es esencialmente "incorrecta". Dada la expresión x % y, A) si xes negativo, el resto es negativo, es decir x % y == -(-x % y). B) el signo de yno tiene ningún efecto, es decirx % y == x % -y
bohemio
72

Dado que "matemáticamente" ambos son correctos:

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

Una de las opciones tuvo que ser elegida por los desarrolladores del lenguaje Java y eligieron:

el signo del resultado es igual al signo del dividendo.

Lo dice en las especificaciones de Java:

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

Caner
fuente
8
La pregunta es "¿por qué Java me da -13 % 64 = 51cuando estaba esperando -13?".
Pascal Cuoq
5
@pascal: java le da la definición correcta en matemáticas y la forma en que se ha implementado para hacer eso no es lo que espera de él.
9
El comportamiento matemáticamente sano está disponible en Java 8: Math.floorMod
Jesse Glick
1
Algo en su 15.17.3. Los ejemplos de % de operador restante no están claros. int result = (-5) % 3;da -2. int result = (-3) % 5;da -3. En general, int result = (-a) % b;da la respuesta correcta cuando | -a | > b. Para obtener el resultado adecuado cuando | -a | <b debemos envolver el divisor. int result = ((-a) % b) + b;para negativo a o int result = (((-a) % b) + b) % b;para positivo o negativo a
Oz Edri
@Caner No entendí esto, ¿cómo podrían ser ambos iguales?
Kishore Kumar Korada
20

¿Estás seguro de que estás trabajando en Java? porque Java da -13% 64 = -13 como se esperaba. ¡El signo del dividendo!

Keyxeq
fuente
15

Su resultado es incorrecto para Java. Proporcione algo de contexto sobre cómo llegó a él (su programa, implementación y versión de Java).

De la especificación del lenguaje Java

15.17.3 Operador restante%
[...]
La operación restante para operandos que son enteros después de la promoción numérica binaria (§5.6.2) produce un valor de resultado tal que (a / b) * b + (a% b) es igual a a.
15.17.2 Operador de división / división
[...]
entera se redondea hacia 0.

Dado que / se redondea hacia cero (resultando en cero), el resultado de% debería ser negativo en este caso.

estrella azul
fuente
Algo en su 15.17.3. Los ejemplos de % de operador restante no están claros. int result = (-5) % 3;da -2 int result = (-3) % 5;da -3 En general, int result = (-a) % b;da la respuesta correcta cuando | -a | > b Para obtener el resultado adecuado cuando | -a | <b debemos envolver el divisor. int result = ((-a) % b) + b;para negativo a o int result = (((-a) % b) + b) % b;para positivo o negativo a.
Oz Edri
1
Tu comentario es bastante confuso. La sección define el resultado correcto y los ejemplos concuerdan con esa definición. Para su ejemplo, (-3) % 5el resultado correcto según la definición es -3, y una implementación correcta de Java debería producir ese resultado.
starblue
Supongo que no me expliqué correctamente. Lo que quise decir con "la respuesta correcta" cuando | -a | <b es que para obtener un resultado positivo debemos "envolver" el resultado dado de a% b añadiéndole b. En mi ejemplo, de (-3)%5hecho da -3, y si queremos el resto positivo debemos agregarle 5, y entonces el resultado será2
Oz Edri
6

puedes usar

(x % n) - (x < 0 ? n : 0);
ruslik
fuente
3
@ruslik También puede hacer: ((x % k) + k) % k. (Aunque el tuyo probablemente sea más legible.)
John Kurlak
2
@JohnKurlak Tu versión funciona así: 4% 3 = 1 O 4% -3 = -2 O -4% 3 = 2 O -4% -3 = -1 pero la de ruslik funciona así: 4% 3 = 1 O 4% -3 = 1 O -4% 3 = -4 O -4% -3 = 2
Joschua
1
@Joschua Gracias por señalar esto. Mi código es útil para cuando desea que el resultado del módulo esté en el rango de en [0, sign(divisor) * divisor)lugar de [0, sign(dividend) * divisor).
John Kurlak
3

Su respuesta está en wikipedia: operación de módulo

Dice que en Java la operación de signo en módulo es la misma que la de dividendo. y dado que estamos hablando del resto de la operación de división está bien, devuelve -13 en su caso, ya que -13/64 = 0. -13-0 = -13.

EDITAR: Lo siento, entendí mal tu pregunta ... Tienes razón, java debería dar -13. ¿Puede proporcionar más código circundante?

Nava Carmon
fuente
2

La aritmética de módulo con operandos negativos la define el diseñador del lenguaje, quien podría dejarlo en manos de la implementación del lenguaje, quien podría diferir la definición a la arquitectura de la CPU.

No pude encontrar una definición de lenguaje Java.
Gracias Ishtar, la especificación del lenguaje Java para el operador restante% dice que el signo del resultado es el mismo que el signo del numerador.

Wallyk
fuente
1

Para superar esto, puede agregar 64(o cualquiera que sea su base de módulo) al valor negativo hasta que sea positivo

int k = -13;
int modbase = 64;

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

int result = k % modbase;

El resultado seguirá estando en la misma clase de equivalencia.

Andreas
fuente
1

x = x + m = x - men módulo m.
así que -13 = -13 + 64en módulo 64 y -13 = 51en módulo 64.
Supongamos Z = X * d + r, si 0 < r < Xentonces en división Z/Xllamamos ral resto.
Z % Xdevuelve el resto de Z/X.


fuente
1

La función mod se define como la cantidad por la cual un número excede el múltiplo entero más grande del divisor que no es mayor que ese número. Entonces en tu caso de

-13 % 64

el mayor múltiplo entero de 64 que no exceda -13 es -64. Ahora, cuando resta -13 de -64 es igual a 51-13 - (-64) = -13 + 64 = 51

Salman Paracha
fuente
0

En mi versión de Java JDK 1.8.0_05 -13% 64 = -13

podría intentar -13- (int (-13/64)) en otras palabras, hacer la división en un número entero para deshacerse de la parte de la fracción y luego restar del numerador Entonces, el numerador- (int (numerador / denominador)) debería dar el correcto resto y signo

Robert Green
fuente
0

En las últimas versiones de Java obtienes -13%64 = -13. La respuesta siempre tendrá signo de numerador.

vsn harish rayasam
fuente
¿En qué versión se realizó este cambio?
NightShadeQueen
En java 7 menciona claramente que mod tendrá el signo del numerador :)
vsn harish rayasam
@NightShadeQueen Nunca se cambió.
Marqués de Lorne
0

De acuerdo con la sección 15.17.3 de la JLS, "La operación de resto para operandos que son enteros después de la promoción numérica binaria produce un valor de resultado tal que (a / b) * b + (a% b) es igual a a. Esta identidad se mantiene incluso en el caso especial de que el dividendo sea el entero negativo de mayor magnitud posible para su tipo y el divisor sea -1 (el resto es 0) ".

Espero que ayude.

kudesiaji
fuente
-1

No creo que Java devuelva 51 en este caso. Estoy ejecutando Java 8 en una Mac y obtengo:

-13 % 64 = -13

Programa:

public class Test {
    public static void main(String[] args) {
        int i = -13;
        int j = 64;
        System.out.println(i % j);
    }
}
ceprateek
fuente
5
@XaverKapeller, ¡no! Mucha gente señaló que matemáticamente hablando -13 y 51 son correctos. En Java, -13 es la respuesta esperada, y es lo que yo también obtuve, así que no sé cómo el remitente obtuvo 51, es un misterio. Los detalles del modo sobre el contexto podrían ayudar a responder correctamente esta pregunta.
Fabyen
@Xaver Kapeller: ¿Cómo pueden ser correctos tanto 51 como -13? Java devolvería solo un valor ..
ceprateek
@XaverKapeller ¿Cómo puede ser incorrecta una respuesta que documente lo que realmente hace Java?
Marqués de Lorne
@EJP Creo que hace 3 años, cuando escribí esto, fui lo suficientemente tonto como para valorar la precisión matemática más que la simple realidad de cómo Java se ocupa de esto. Gracias por recordarme que elimine mi estúpido comentario: D
Xaver Kapeller