Encontrei um comportamento estranho em Python em relação aos números negativos:
>>> -5 % 4
3
Alguém poderia explicar o que está acontecendo?
Encontrei um comportamento estranho em Python em relação aos números negativos:
>>> -5 % 4
3
Alguém poderia explicar o que está acontecendo?
..., -9, -5, -1, 3, 7, ...
math.fmod
para obter o mesmo comportamento que em C ou Java.
Respostas:
Ao contrário de C ou C ++, o operador de módulo do Python ( %
) sempre retorna um número com o mesmo sinal do denominador (divisor). Sua expressão produz 3 porque
(-5) / 4 = -1,25 -> piso (-1,25) = -2
(-5)% 4 = (-2 × 4 + 3)% 4 = 3.
Ele é escolhido em vez do comportamento C porque um resultado não negativo costuma ser mais útil. Um exemplo é calcular os dias da semana. Se hoje é terça-feira (dia 2), qual é o dia da semana N dias antes? Em Python podemos computar com
return (2 - N) % 7
mas em C, se N ≥ 3, obtemos um número negativo que é um número inválido e precisamos corrigi-lo manualmente adicionando 7:
int result = (2 - N) % 7;
return result < 0 ? result + 7 : result;
(Consulte http://en.wikipedia.org/wiki/Modulo_operator para saber como o sinal do resultado é determinado para diferentes idiomas.)
Aqui está uma explicação de Guido van Rossum:
http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
Essencialmente, é assim que a / b = q com o resto r preserva as relações b * q + r = a e 0 <= r <b.
a
, positivo b
, enquanto os pisos de Python. É sempre verdade isso abs(r) < b
, e eles se fecham r <= 0
.
Não existe uma maneira melhor de lidar com a divisão de inteiros e mods com números negativos. Seria bom se a/b
fosse da mesma magnitude e sinal oposto de (-a)/b
. Seria bom se a % b
fosse mesmo um módulo b. Como realmente queremos a == (a/b)*b + a%b
, os dois primeiros são incompatíveis.
Qual delas manter é uma questão difícil e há argumentos para ambos os lados. C e C ++ arredondam a divisão inteira para zero (portanto a/b == -((-a)/b)
), e aparentemente o Python não.
Como apontado, o módulo Python é uma exceção bem fundamentada às convenções de outras linguagens.
Isso dá aos números negativos um comportamento contínuo, especialmente quando usados em combinação com o //
operador de divisão de inteiros, como o %
módulo costuma ser (como em matemática. Divmod ):
for n in range(-8,8):
print n, n//4, n%4
Produz:
-8 -2 0
-7 -2 1
-6 -2 2
-5 -2 3
-4 -1 0
-3 -1 1
-2 -1 2
-1 -1 3
0 0 0
1 0 1
2 0 2
3 0 3
4 1 0
5 1 1
6 1 2
7 1 3
%
sempre produz zero ou positivo *//
sempre gira em direção ao infinito negativo* ... desde que o operando correto seja positivo. Por outro lado11 % -10 == -9
Em python , o operador módulo funciona assim.
>>> mod = n - math.floor(n/base) * base
então o resultado é (para o seu caso):
mod = -5 - floor(-1.25) * 4
mod = -5 - (-2*4)
mod = 3
enquanto outras linguagens como C, JAVA e JavaScript usam truncamento em vez de floor.
>>> mod = n - int(n/base) * base
o que resulta em:
mod = -5 - int(-1.25) * 4
mod = -5 - (-1*4)
mod = -1
Se você precisar de mais informações sobre arredondamento em python, leia isto .
Módulo, classes de equivalência para 4:
Aqui está um link para o comportamento do módulo com números negativos . (Sim, eu pesquisei)
Também achei que era um comportamento estranho do Python. Acontece que eu não estava resolvendo bem a divisão (no papel); Eu estava atribuindo um valor de 0 ao quociente e um valor de -5 ao restante. Terrível ... Esqueci a representação geométrica dos números inteiros. Ao relembrar a geometria dos inteiros dada pela reta numérica, pode-se obter os valores corretos para o quociente e o restante e verificar se o comportamento do Python está correto. (Embora eu presuma que você já resolveu sua preocupação há muito tempo).
Também vale a pena mencionar que também a divisão em python é diferente de C: Considere
>>> x = -10
>>> y = 37
em C você espera o resultado
0
o que é x / y em python?
>>> print x/y
-1
e% é módulo - não o resto! Enquanto x% y em C produz
-10
python produz.
>>> print x%y
27
Você pode obter tanto como em C
A divisão:
>>> from math import trunc
>>> d = trunc(float(x)/y)
>>> print d
0
E o restante (usando a divisão acima):
>>> r = x - d*y
>>> print r
-10
Este cálculo talvez não seja o mais rápido, mas está funcionando para qualquer combinação de sinais de xey para obter os mesmos resultados que em C, além de evitar declarações condicionais.