Estou tentando modificar um número inteiro para obter uma posição de matriz para que ele faça um loop redondo. Fazer i %
arrayLength
funciona bem para números positivos, mas para números negativos tudo dá errado.
4 % 3 == 1
3 % 3 == 0
2 % 3 == 2
1 % 3 == 1
0 % 3 == 0
-1 % 3 == -1
-2 % 3 == -2
-3 % 3 == 0
-4 % 3 == -1
então eu preciso de uma implementação de
int GetArrayIndex(int i, int arrayLength)
de tal modo que
GetArrayIndex( 4, 3) == 1
GetArrayIndex( 3, 3) == 0
GetArrayIndex( 2, 3) == 2
GetArrayIndex( 1, 3) == 1
GetArrayIndex( 0, 3) == 0
GetArrayIndex(-1, 3) == 2
GetArrayIndex(-2, 3) == 1
GetArrayIndex(-3, 3) == 0
GetArrayIndex(-4, 3) == 2
Eu já fiz isso antes, mas por algum motivo está derretendo meu cérebro hoje :(
Respostas:
Eu sempre uso minha própria
mod
função, definida comoClaro, se você está preocupado em ter duas chamadas para a operação do módulo, você pode escrevê-lo como
ou variantes dos mesmos.
A razão pela qual isso funciona é que "x% m" está sempre no intervalo [-m + 1, m-1]. Portanto, se for negativo, adicionar m a ele o colocará na faixa positiva sem alterar seu valor módulo m.
fonte
r = x%m
é-1
, após o quer+m
é1
. O loop while não é necessário. O ponto é que (como escrevi na resposta),x%m
é sempre estritamente maior que-m
, então você precisa adicionarm
no máximo uma vez para torná-lo positivo.r
paraa
modulob
, então é tal que 0 ≤ r <| b |.Observe que o operador% C # e C ++ não é realmente um módulo, é o restante. A fórmula para o módulo que você deseja, no seu caso, é:
Você precisa recodificar isso em C # (ou C ++), mas é assim que obtém o módulo e não o restante.
fonte
-21 mod 4 is 3 because -21 + 4 x 6 is 3.
Mas-21 divided by 4 gives -5
com aremainder of -1
. Para valores positivos, não há diferença. Portanto, informe-se sobre essas diferenças. E não confie na Wikipedia o tempo todo :) #%
restante?Implementação de linha
%
única usando apenas uma vez:fonte
mod(-10, 6)
à mão, você adiciona ou subtrai 6 repetidamente até que a resposta esteja no intervalo[0, 6)
. Essa notação significa "inclusivo à esquerda e exclusivo à direita". No nosso caso, adicionamos 6 duas vezes, fornecendo 2. O código é bastante simples e é fácil perceber que está certo: primeiro, ele equivale a adicionar / subtrairn
como acima, exceto que ele para umn
pouco, se estiver se aproximando de o lado negativo. Nesse caso, nós corrigimos isso. LÁ: comentários :)%
pode ser uma boa ideia. Consulte a tabela Quanto custa o código gerenciado no artigo Escrevendo código gerenciado mais rápido: Saiba o que custa . O uso%
é similar aoint div
listado na tabela: cerca de 36 vezes mais caro do que adicionar ou subtrair e 13 vezes mais caro do que multiplicar. Obviamente, não é grande coisa, a menos que isso esteja no cerne do que seu código está fazendo.%
mais caro que um teste e um salto, especialmente se não puder ser facilmente previsto?A resposta de ShreevatsaR não funcionará para todos os casos, mesmo se você adicionar "se (m <0) m = -m;", se você considerar dividendos / divisores negativos.
Por exemplo, -12 mod -10 será 8 e deve ser -2.
A implementação a seguir funcionará para dividendos / divisores positivos e negativos e está em conformidade com outras implementações (Java, Python, Ruby, Scala, Scheme, Javascript e Calculadora do Google):
Conjunto de testes usando xUnit:
fonte
mod
função geralmente é chamada com módulo positivo (observe a variávelarrayLength
na pergunta original que está sendo respondida aqui, que provavelmente nunca é negativa), portanto, a função não precisa realmente ser feita para funcionar com o módulo negativo. (É por isso que eu mencionar o tratamento de módulo negativo em um comentário sobre a minha resposta, não na própria resposta.) (Cont ...)r = a - b floor(a/b)
é sempre positivo). Mesmo entre os sistemas de computadores, Pascal e Maple, por exemplo, definem que é sempre positivo.Adicionando alguma compreensão.
Pela definição euclidiana, o resultado da modificação deve ser sempre positivo.
Ex:
Resultado:
fonte
-1
?the positive remainder is always chosen
mas as linguagens de programação escolhem dependendo da linguagem e dos sinais de a e / ou n. [5] Padrão Pascal e Algol68 dar um resto positivo (ou 0), mesmo para divisores negativas, e algumas linguagens de programação, tais como C90, deixá-lo até a implementação quando uma das n ou é negative.`Comparando duas respostas predominantes
e
Na verdade, ninguém mencionou o fato de que o primeiro pode dar um
OverflowException
tempo enquanto o segundo não. Pior ainda, com o contexto desmarcado padrão, a primeira resposta pode retornar a resposta errada (veja,mod(int.MaxValue - 1, int.MaxValue)
por exemplo). Portanto, a segunda resposta não apenas parece mais rápida, mas também mais correta.fonte
Basta adicionar seu módulo (arrayLength) ao resultado negativo de% e você ficará bem.
fonte
Para os desenvolvedores mais atentos ao desempenho
Uma pequena comparação de desempenho
Quanto ao custo de desempenho do elenco para o uint, dê uma olhada aqui
fonte
-3 % 10
devem ser -3 ou 7. Como se deseja um resultado não negativo, 7 seria a resposta. Sua implementação retorna 3. Você deve alterar os dois parâmetrosuint
e remover a conversão.n
for uma potência de dois; nesse caso, você pode simplesmente usar um lógico e ((uint)k & (n - 1)
), se o compilador ainda não fizer isso por você (os compiladores geralmente são inteligentes o suficiente para descobrir isso).Gosto do truque apresentado por Peter N Lewis neste tópico : "Se n tiver um intervalo limitado, você poderá obter o resultado desejado simplesmente adicionando um múltiplo constante conhecido do [divisor] que é maior que o valor absoluto do mínimo."
Então, se eu tenho um valor d que está em graus e quero tirar
e quero evitar os problemas se d for negativo, em vez disso, basta fazer o seguinte:
Isso pressupõe que, embora d possa ser negativo, sabe-se que nunca será mais negativo que -720.
fonte
%
.Você espera um comportamento contrário ao comportamento documentado do operador% em c # - possivelmente porque espera que ele funcione de uma maneira que funcione em outro idioma com o qual você está mais acostumado. A documentação sobre estados c # (ênfase minha):
O valor que você deseja pode ser calculado com uma etapa extra:
fonte
Uma implementação de linha única da resposta do dcastro (a mais compatível com outros idiomas):
Se você deseja manter o uso do
%
operador (não é possível sobrecarregar os operadores nativos em C #):Caso de uso, ambos funcionam:
fonte
Todas as respostas aqui funcionam muito bem se o seu divisor for positivo, mas não está completo. Aqui está minha implementação, que sempre retorna em um intervalo de
[0, b)
, de modo que o sinal da saída seja o mesmo que o sinal do divisor, permitindo divisores negativos como o ponto final do intervalo de saída.PosMod(5, 3)
retorna2
PosMod(-5, 3)
retorna1
PosMod(5, -3)
retorna-1
PosMod(-5, -3)
retorna-2
(onde
real_t
pode ser qualquer tipo de número)fonte