A versão que usa bit a bit e (&) é muito mais eficiente que a versão do módulo (%). Você deve alterar o que selecionou como a resposta correta.
Stefan Rusek 02/10/08
6
Improvável que isso importe - o argumento é uma constante. Fácil para o otimizador
MSalters 2/08/08
2
Fatores de legibilidade para isso também.
Brian G
2
Em aplicativos incorporados (o mundo em que passo a maior parte do tempo em programação), alguns processadores possuem unidades aritméticas muito primitivas e não podem executar operações de divisão / módulo facilmente. Por esse motivo, geralmente uso o método bit a bit. No entanto, na CPU de um desktop moderno, esse não será o caso.
bta
3
Nunca achei a operação do módulo mais fácil de entender. Quando eu precisei determinar par ou ímpar, a máscara bit a bit foi a primeira coisa que me veio à mente. É algo natural, já que a maneira como fazemos isso manualmente é olhar o dígito menos significativo para ver se está em {0 2 4 6 8} ou {1 3 5 7 9}. Isso se traduz diretamente para olhar para o bit menos significativo para ver se é 0 ou 1.
P Daddy
Respostas:
449
Use o operador modulo (%) para verificar se há um restante ao dividir por 2:
if(x %2){/* x is odd */}
Algumas pessoas criticaram minha resposta acima afirmando que usar x & 1 é "mais rápido" ou "mais eficiente". Não acredito que seja esse o caso.
Por curiosidade, criei dois programas triviais de casos de teste:
/* modulo.c */#include<stdio.h>int main(void){int x;for(x =0; x <10; x++)if(x %2)
printf("%d is odd\n", x);return0;}/* and.c */#include<stdio.h>int main(void){int x;for(x =0; x <10; x++)if(x &1)
printf("%d is odd\n", x);return0;}
Em seguida, compilei isso com o gcc 4.1.3 em uma de minhas máquinas 5 vezes diferentes:
Sem sinalizadores de otimização.
Com -O
Com -Os
Com -O2
Com -O3
Examinei a saída de montagem de cada compilação (usando gcc-S) e descobri que, em cada caso, a saída para and.c e modulo.c eram idênticas (ambos usavam a instrução andl $ 1,% eax). Duvido que esse seja um "novo" recurso, e suspeito que remonta a versões antigas. Também duvido que qualquer compilador não arcano moderno (comercializado nos últimos 20 anos), de código aberto ou comercial, não tenha essa otimização. Eu testaria em outros compiladores, mas não tenho nenhum disponível no momento.
Se alguém mais gostaria de testar outros compiladores e / ou destinos de plataforma e obtiver um resultado diferente, eu ficaria muito interessado em saber.
Finalmente, a versão do módulo é garantida pelo padrão para trabalhar se o número inteiro é positivo, negativo ou zero, independentemente da representação da implementação de números inteiros assinados. A versão bit a bit e não é. Sim, eu sei que o complemento de dois é onipresente, então isso não é realmente um problema.
A pergunta perguntou especificamente como fazê-lo em C, então eu respondi em C, apesar de chustar mencionar que eles não conseguiram descobrir como fazê-lo em Java. Não reivindiquei ou impliquei que essa era uma resposta do Java, não sei o Java. Acho que acabei de receber meu primeiro voto negativo e estou confuso sobre o porquê. Ah bem.
Chris Young
33
Eu diria, se (x% 2! = 0) {/ * x é ímpar * /}, mas quem sabe. Também não sei java.
eugensk
9
Está recebendo muitos votos positivos para diferenciá-lo dos idiotas dos operadores bit a bit, sem ter que gastar nosso karma votando neles.
Wnoise 02/10/08
13
Eu concordo com tudo, exceto uma coisa: eu gosto de manter inteiros e valores de verdade separados, conceitualmente, então prefiro escrever "se (x% 2 == 1)". É o mesmo para o compilador, mas talvez um pouco mais claro para os seres humanos. Além disso, você pode usar o mesmo código em idiomas que não interpretam diferente de zero como verdadeiro.
Thomas Padron-McCarthy
46
Minha referência? Qual referência? Eu não fiz nenhum benchmarking. Examinei a linguagem assembly gerada. Isso não tem absolutamente nada a ver com printf.
317 Chris Young
207
Vocês são muito eficientes. O que você realmente quer é:
public boolean isOdd(int num){int i =0;
boolean odd =false;while(i != num){
odd =!odd;
i = i +1;}return odd;}
Repita para isEven .
Claro, isso não funciona para números negativos. Mas com brilho vem o sacrifício ...
Se você lançou uma exceção de argumento em valores negativos e observou na documentação que esta função é O (N), então eu ficaria bem com isso.
Jeffrey L Whitledge
7
A versão corporativa teria que usar XML. É claro que hoje em dia você teria um serviço da web que poderia consultar
Martin Beckett
58
Você deve otimizar isso com uma tabela de consulta.
Weeble
1
Eu sou um monge, tinha de um seu representante 6.999 em um novo milênio
Eran Medan
7
Isto é brilhante! Meu chefe me disse que tínhamos um cliente irritado porque achava que sua licença corporativa não dava nada além da licença padrão. Agora nós adicionamos essa função em nosso programa, e só porque é executado mais lentamente, ele acha que seu software está fazendo MUITO mais trabalho !!!
Não acho justo dizer que é mais rápido do que usar divisão ou módulo. O padrão C não diz nada sobre o desempenho dos operadores, e qualquer compilador decente produzirá código rápido para ambos. Eu pessoalmente escolher o idioma que se comunica a minha intenção, e% parece mais apropriado aqui
Chris Young
21
Eu gosto mais de (x e 1), porque verifica se o número é igual ao das pessoas: verifique se o último dígito é par ou ímpar. Na minha opinião, ele comunica sua intenção mais do que o método modulo. (Não que isso importe muito.)
Jeremy Ruten
2
Você está certo, acho que é subjetivo. Embora a definição usual de "par" seja "número inteiro divisível por 2", não "número inteiro que termina em 0, 2, 4, 6 ou 8". :-)
Chris Young
4
@TraumaPony - para ANSI padrão C e Java inicial, depende do sistema do computador. É especificado que a representação é usado para números assinados - 2 de elogio, elogio 1 do, cinza-codificado, etc. Mas módulo é sempre módulo
Aaron
9
Não funciona universalmente para números negativos. Consulte Verifique esta resposta para obter mais detalhes: stackoverflow.com/questions/160930/… para obter detalhes.
Uau ... isso é mais louco do que a solução do SCdF! Parabéns! Não há voto positivo ... não posso recomendar isso. Mas obrigado pelo engraçado!
Wes P
1
A vantagem dessa abordagem é que ela trabalha com mais do que apenas números. Além disso, se você substituir esta linha: char bar = foo [foo.Length - 1]; com isso: barra dupla = Char.GetNumericValue (foo [foo.Length - 1]); Então ele funcionará com qualquer sistema numérico.
Jeffrey L Whitledge
5
relatório de erro: 14.65 é relatado como ímpar quando deveria ser desconhecido.
TheSoftwareJedi 22/10/08
4
Software Jedi, é um "recurso". ;)
Sklivvz 23/10/08
31
TheSoftwareJedi: 14.65 é um dos números inteiros mais estranhos que eu já vi.
Bruce Alderman
16
Em resposta ao ffpf - eu tive exatamente o mesmo argumento com um colega anos atrás, e a resposta é não , ele não funciona com números negativos.
O padrão C estipula que números negativos podem ser representados de três maneiras:
Complemento 2
Complemento 1
sinal e magnitude
Verificando assim:
isEven =(x &1);
funcionará no complemento de 2 e na representação de sinal e magnitude, mas não no complemento de 1.
No entanto, acredito que o seguinte funcionará para todos os casos:
isEven =(x &1)^((-1&1)|((x <0)?0:1)));
Agradeço ao ffpf por apontar que a caixa de texto estava comendo tudo depois do meu personagem menor que o!
Acho que seu segundo exemplo de código está faltando algum texto.
Jeff Yates
3
Vamos elogiar esses números!
thejh 30/03
14
Uma boa é:
/*forward declaration, C compiles in one pass*/bool isOdd(unsignedint n);bool isEven(unsignedint n){if(n ==0)returntrue;// I know 0 is evenelsereturn isOdd(n-1);// n is even if n-1 is odd}bool isOdd(unsignedint n){if(n ==0)returnfalse;elsereturn isEven(n-1);// n is odd if n-1 is even}
Observe que esse método usa recursão de cauda envolvendo duas funções. Ele pode ser implementado com eficiência (transformado em um tipo de loop de tempo / até) se o seu compilador suportar recursão de cauda como um compilador Scheme. Nesse caso, a pilha não deve transbordar!
Eu acho que você tem um loop infinito (com recursão de cauda) ou um estouro de pilha (sem recursão de cauda) para isOdd () com quaisquer valores pares ou isEven () com valores ímpares. Só termina com true. É o problema da parada novamente.
Jeffrey L Whitledge
7
Ah, claro, conserte-o sem comentários e faça-me parecer um idiota. Isso é bom.
Jeffrey L Whitledge
1
Agora, você tem um erro de compilação: em isEven nem todos os caminhos de código retornam um valor. Não, eu realmente não tentei esse código, é o compilador na minha cabeça que está reclamando.
Jeffrey L Whitledge
5
erro de compilação: nem todos os caminhos de retornar um valor ódio para bombardeá-lo com comentários de bugs em seu código de exemplo, mas o que acontece quando você chamar eIgual (5)
Kevin
11
Um número é par se, quando dividido por dois, o restante for 0. Um número será ímpar se, quando dividido por 2, o restante for 1.
// Javapublicstatic boolean isOdd(int num){return num %2!=0;}/* C */int isOdd(int num){return num %2;}
Seu método Java está quebrado porque num% 2 == -1 para números ímpares negativos.
WMR 22/10/08
Foi por isso que você me rebaixou?
Jjnguy 22/10/08
3
Eu diminuí a votação porque sua função em C leva mais caracteres para digitar do que aquilo que faz. IE num% I tem 7 caracteres, incluindo os espaços IsOdd (I) 8 caracteres. Por que você criaria uma função que é mais longa do que apenas executar a operação?
22408 Kevin
13
@ Kevin, na minha opinião, o código não é medido por caracteres, mas pelo tempo que você leva para escrevê-lo, incluindo o tempo de reflexão + de depuração. num% 2 leva um milissegundo a mais para pensar do que isOdd. agora adicione os números globalmente e você perdeu um ano coletivo. O isOdd também pode ser testado, verificado e eventualmente certificado como livre de bugs (por exemplo, manipulação de números negativos) em que% 2 - alguns desenvolvedores sempre têm dúvidas e experimentam. código bom é o código que você não escreve, apenas reutiliza ... apenas meus 2 centavos.
Eran Medan
2
@EranMedan, a mesma lógica se aplicaria à substituição do i ++ pelo IncrementByOne (i) e é uma idéia tão ruim quanto. Se um desenvolvedor tiver dúvidas sobre o que% 2 faz, não o quero nem perto do meu código.
Não, você não é o tipo de criança que contou com :)
eugensk
Eu ia aprovar isso, mas é um pouco lento em números negativos. :)
Chris Young
3
Todos os números são brilhantes e positivos. Ou você tem preconceito contra alguns? :))
eugensk
3
Nos computadores, todos os números negativos, eventualmente se tornam positivos. Chamamos isso de Rollover of Happiness (não aplicável a BIGNUMS, YMMY, não é válido em todos os estados).
Will Hartung
@WillHartung "rolagem de felicidade" é ótimo! : D
thejh 30/03
6
Eu criaria uma tabela de paridades (0 se 1 igual a ímpar) dos números inteiros (para que se pudesse fazer uma pesquisa: D), mas o gcc não me permite fazer matrizes de tamanhos iguais:
Então, vamos recorrer à definição matemática de par e ímpar.
Um número inteiro n é uniforme se existir um número inteiro k tal que n = 2k.
Um número inteiro n é ímpar se existir um número k tal que n = 2k + 1.
Aqui está o código para isso:
char even (int n){int k;for(k = INT_MIN; k <= INT_MAX;++k){if(n ==2* k){return1;}}return0;}char odd (int n){int k;for(k = INT_MIN; k <= INT_MAX;++k){if(n ==2* k +1){return1;}}return0;}
Let C-inteiros denotam os possíveis valores de intem uma dada compilação C. (Observe que C-inteiros é um subconjunto dos inteiros.)
Agora, pode-se preocupar que, para um dado n em C-inteiros, o número inteiro correspondente k possa não existir em C-inteiros. Mas com uma pequena prova, pode-se mostrar que para todos os números inteiros n, | n | <= | 2n | (*), onde | n | é "n se n for positivo e -n caso contrário". Em outras palavras, para todos os n em números inteiros, pelo menos um dos itens a seguir é válido (exatamente os casos (1 e 2) ou os casos (3 e 4), de fato, mas não vou provar aqui):
Caso 1: n <= 2n.
Caso 2: -n <= -2n.
Caso 3: -n <= 2n.
Caso 4: n <= -2n.
Agora pegue 2k = n. (Tal ak existe se n for par, mas eu não vou provar aqui. Se n for par, o loop in evennão retornará mais cedo, portanto não importa.) Mas isso implica k <n se n não 0 por (*) e o fato (novamente não provado aqui) de que para todo m, z em números inteiros 2m = z implica z diferente de m dado m não é 0. No caso n é 0, 2 * 0 = 0 então 0 é o mesmo que terminamos (se n = 0 então 0 está em números inteiros C porque n está em números inteiros C na funçãoeven , portanto, k = 0 está em números inteiros C). Assim, tal ak em C-inteiros existe para n em C-inteiros se n for par.
Um argumento semelhante mostra que se n é ímpar, existe ak em números inteiros C de modo que n = 2k + 1.
Portanto, as funções evene oddapresentadas aqui funcionarão corretamente para todos os C-inteiros.
Você pode explicar isso, por favor? Estou muito familiarizado com operadores bit a bit
Abdul
Deslocar para a direita e depois para a esquerda zerará seu último bit (o mais correto). Se o novo número for igual ao original, isso significa que o último bit do número original foi 0. Portanto, é par. Dê uma olhada na minha resposta atualizada.
Kiril Aleksandrov
obrigado, eu obtê-lo agora
Abdul
Não tenho certeza de qual abordagem é mais rápida. Não tentei compará-los.
Kiril Aleksandrov
Isso também não zera o seu bit mais significativo? Um problema com ints não assinados em alguns idiomas e ints negativos na maioria ...
Troyseph
4
Lendo essa discussão bastante divertida, lembrei que tinha uma função sensível ao tempo no mundo real que testava números ímpares e pares dentro do loop principal. É uma função de potência inteira, publicada em outro lugar no StackOverflow, da seguinte maneira. Os benchmarks foram bastante surpreendentes. Pelo menos nessa função do mundo real, o módulo é mais lento e significativamente mais. O vencedor, por uma ampla margem, exigindo 67% do tempo do módulo, é uma abordagem ou (|) , e não pode ser encontrado em nenhum outro lugar nesta página.
static dbl IntPow(dbl st0,int x){
UINT OrMask= UINT_MAX -1;
dbl st1=1.0;if(0==x)return(dbl)1.0;while(1!= x){if(UINT_MAX ==(x|OrMask)){// if LSB is 1... //if(x & 1) {//if(x % 2) {
st1 *= st0;}
x = x >>1;// shift x right 1 bit...
st0 *= st0;}return st1 * st0;}
Para 300 milhões de loops, os tempos de referência são os seguintes.
3.962 the | e abordagem de máscara
4.851 a abordagem
5.850 a abordagem%
Para pessoas que pensam que a teoria, ou uma listagem em linguagem assembly, resolve argumentos como esses, isso deve ser um conto de advertência. Há mais coisas no céu e na terra, Horácio, do que se sonha em sua filosofia.
Melhor usar unsigned xcomo x = x >> 1;é o comportamento definido pela implementação quando x < 0. Não está claro por que xe OrMaskdiferem em tipo. Simples o suficiente para reescrever usando um while(x)teste.
chux - Restabelece Monica
2
Gostaria de saber qual compilador você usou para comparar isso, já que a maioria dos compiladores deve ser inteligente o suficiente para compilar o % 2caso usando o bit a bit &. Acabei de testar isso e os resultados são os mesmos (VS2015, a versão é compilada com todas as otimizações, x86 e x64). A resposta aceita também afirma isso para o GCC (escrito em 2008).
Lou
2
O problema com este post é que a premissa de que um bit a bit orseria mais rápido que um andé altamente improvável, em qualquer plataforma / compilador. Mesmo se houvesse uma combinação estranha de plataforma / compilador (e você não publicou nem isso nem o código usado para realizar a referência), dependendo de outros compiladores que se comportam da mesma forma, seria uma má aposta de otimização. Então, como eu escrevi, me pergunto em qual plataforma / compilador isso foi testado , porque tenho quase certeza de que não foi medido corretamente.
Lou
2
Não o chamando de mentiroso, apenas afirmando com alta certeza que você não mediu corretamente. Não há necessidade de me chamar de motorista de caminhão ainda, leia meu comentário original: fiz um benchmark e os resultados foram, como esperado, completamente iguais nos três casos (certeza de ~ 3 sigma, depois de executar cada teste 10 vezes por 500.000 .000 iterações). Se você realmente tem uma longa carreira ilustre, dê um passo atrás e pense se suas reivindicações fazem sentido e publique o código real usado para fazer a referência. Caso contrário, o post é o que eu acredito que seja, apenas um erro de medição.
Este é um acompanhamento da discussão com o @RocketRoy sobre sua resposta , mas pode ser útil para quem quiser comparar esses resultados.
tl; dr Pelo que tenho visto, a abordagem de Roy ( (0xFFFFFFFF == (x | 0xFFFFFFFE)) não está totalmente otimizado para x & 1que a modabordagem, mas na prática tempos de execução deve vir iguais em todos os casos.
Então, primeiro comparei a saída compilada usando o Compiler Explorer :
Funções testadas:
int isOdd_mod(unsigned x){return(x %2);}int isOdd_and(unsigned x){return(x &1);}int isOdd_or(unsigned x){return(0xFFFFFFFF==(x |0xFFFFFFFE));}
CLang 3.9.0 com -O3:
isOdd_mod(unsignedint):# @isOdd_mod(unsigned int)
and edi,1
mov eax, edi
ret
isOdd_and(unsignedint):# @isOdd_and(unsigned int)
and edi,1
mov eax, edi
ret
isOdd_or(unsignedint):# @isOdd_or(unsigned int)
and edi,1
mov eax, edi
ret
GCC 6.2 com -O3:
isOdd_mod(unsignedint):
mov eax, edi
and eax,1
ret
isOdd_and(unsignedint):
mov eax, edi
and eax,1
ret
isOdd_or(unsignedint):
or edi,-2
xor eax, eax
cmp edi,-1
sete al
ret
Com o clang, percebemos que todos os três casos são funcionalmente iguais. No entanto, a abordagem de Roy não é otimizada no GCC, portanto, YMMV.
É semelhante ao Visual Studio; inspecionando a desmontagem do Release x64 (VS2015) para essas três funções, pude ver que a parte de comparação é igual para os casos "mod" e "e" e "e um pouco maior para o caso" ou "de Roy:
// x % 2
test bl,1
je (some address)// x & 1
test bl,1
je (some address)// Roy's bitwise or
mov eax,ebx
or eax,0FFFFFFFEh
cmp eax,0FFFFFFFFh
jne (some address)
No entanto, após executar uma referência real para comparar essas três opções (modificação simples, bit a bit ou bit a bit e), os resultados foram completamente iguais (novamente, Visual Studio 2005 x86 / x64, versão Build, sem depurador anexado).
A montagem de liberação usa as testinstruções para andemod casos, enquanto o caso de Roy usa a cmp eax,0FFFFFFFFhabordagem, mas é fortemente desenrolada e otimizada para que não haja diferença na prática.
Meus resultados após 20 execuções (i7 3610QM, plano de energia do Windows 10 definido como Alto desempenho):
[Teste: Modificação simples 2] TEMPO MÉDIO: 689,29 ms (Dif. Relativa: + 0,000%)
[Teste: Bit a bit ou] TEMPO MÉDIO: 689,63 ms (Diferença relativa: + 0,048%)
[Teste: Bit a bit e] TEMPO MÉDIO: 687,80 ms (Dif. Relativa: -0,217%)
A diferença entre essas opções é menor que 0,3%; portanto, é óbvio que a montagem é igual em todos os casos.
Aqui está o código, se alguém quiser tentar, com uma ressalva de que eu apenas o testei no Windows (verifique o #if LINUXcondicional para a get_timedefinição e implemente-o, se necessário, retirado desta resposta ).
Eu acredito que você cometeu o Cardeal Sin de comparações; criando um tão específico que não representa um ambiente do mundo real. Veja a linguagem assembly e observe quantos registros você está usando. Marcas altas de esforço, mas esses resultados não se sustentam no processamento no mundo real.
@RocketRoy: como todas as saídas são exatamente iguais para os três casos (bem, um pouco pior para o seu programa em um caso), eu realmente não me importo com quantos registros foram usados. Porém, novamente, sinta-se à vontade para criar e publicar um programa / ambiente de exemplo que confunda o compilador para criar um assembly mais otimizado em um dos casos, sendo tudo o mesmo.
Lou
Eu sempre gosto de programadores arrogantes. É uma boa característica para um programador, mas em um programa do mundo real mais complexo, meu método terá um desempenho melhor que o seu, porque o compilador tem mais maneiras de resolver o problema para que as instruções se sobreponham (nas arquiteturas Intel) produzindo melhores resultados . Muito poucos programadores veteranos com boa experiência em benchmarking preferem seu benchmark, mas continuem com o bom trabalho e lembre-se de executar novamente seus benchmarks quando novos lançamentos de chips forem lançados. As coisas mudam com o tempo.
3
Eu sei que isso é apenas açúcar sintático e aplicável apenas em .net, mas e o método de extensão ...
O método bit a bit depende da representação interna do número inteiro. O módulo funcionará em qualquer lugar onde houver um operador de módulo. Por exemplo, alguns sistemas realmente usam os bits de baixo nível para marcação (como linguagens dinâmicas), para que o x & 1 bruto não funcione nesse caso.
Prova de correção - considere o conjunto de todos os números inteiros positivos e suponha que exista um conjunto de números inteiros não vazios que não sejam ímpares. Como números inteiros positivos são bem ordenados, haverá um número menor e não ímpar, o que por si só é bastante ímpar, tão claramente que esse número não pode estar no conjunto. Portanto, este conjunto não pode estar vazio. Repita para números inteiros negativos, exceto procure o maior número não ímpar.
if((x &1)==0)
total +=1;//even numberelse
total -=1;//odd numberSystem.Math.DivRem((long)x,(long)2, out outvalue);if( outvalue ==0)
total +=1;//even numberelse
total -=1;//odd numberif(((x /2)*2)== x)
total +=1;//even numberelse
total -=1;//odd numberif(((x >>1)<<1)== x)
total +=1;//even numberelse
total -=1;//odd numberwhile(index >1)
index -=2;if(index ==0)
total +=1;//even numberelse
total -=1;//odd number
tempstr = x.ToString();
index = tempstr.Length-1;//this assumes base 10if(tempstr[index]=='0'|| tempstr[index]=='2'|| tempstr[index]=='4'|| tempstr[index]=='6'|| tempstr[index]=='8')
total +=1;//even numberelse
total -=1;//odd number
Quantas pessoas conheciam o método Math.System.DivRem ou por que o usariam?
Para dar mais detalhes sobre o método do operador bit a bit para aqueles que não fizeram muita álgebra booleana durante nossos estudos, aqui está uma explicação. Provavelmente não é de muita utilidade para o OP, mas eu queria deixar claro por que o NUMBER & 1 funciona.
Observe que, como alguém respondeu acima, a maneira como os números negativos são representados pode interromper o funcionamento desse método. De fato, ele também pode quebrar o método do operador de módulo, pois cada idioma pode diferir na maneira como lida com operandos negativos.
No entanto, se você souber que NUMBER sempre será positivo, isso funcionará bem.
Como Tooony acima mencionou, apenas o último dígito em binário (e negação) é importante.
Uma lógica AND booleana dita que ambas as entradas devem ser 1 (ou alta tensão) para que 1 seja retornado.
1 e 0 = 0.
0 e 1 = 0.
0 e 0 = 0.
1 e 1 = 1.
Se você representa qualquer número como binário (usei uma representação de 8 bits aqui), os números ímpares têm 1 no final, os números pares têm 0.
Por exemplo:
1 = 00000001
2 = 00000010
3 = 00000011
4 = 00000100
Se você pegar qualquer número e usar AND bit a bit (& em java) por 1, retornará 00000001, = 1, o que significa que o número é ímpar. Ou 00000000 = 0, significando que o número é par.
Por exemplo
É estranho?
1 & 1 =
00000001 &
00000001 =
00000001 <- Ímpar
2 & 1 =
00000010 &
00000001 =
00000000 <- Par
54 & 1 =
00000001 &
00110110 =
00000000 <- Par
É por isso que isso funciona:
if(number &1){//Number is odd}else{//Number is even}
# defining function for number parity check
def parity(number):"""Parity check function"""# if number is 0 (zero) return 'Zero neither ODD nor EVEN',# otherwise number&1, checking last bit, if 0, then EVEN, # if 1, then ODD.return(number ==0 and 'Zero neither ODD nor EVEN') \
or (number&1 and 'ODD' or 'EVEN')# cycle trough numbers from 0 to 13 for number in range(0,14):
print "{0:>4} : {0:08b} : {1:}".format(number, parity(number))
Resultado:
0:00000000:Zero neither ODD nor EVEN
1:00000001: ODD
2:00000010: EVEN
3:00000011: ODD
4:00000100: EVEN
5:00000101: ODD
6:00000110: EVEN
7:00000111: ODD
8:00001000: EVEN
9:00001001: ODD
10:00001010: EVEN
11:00001011: ODD
12:00001100: EVEN
13:00001101: ODD
@ el.pescado, obrigado. Se Zero é par, quantos pares ele tem?
@ el.pescado, Ok, concordo com você. Então, se pensar um pouco, por que dividimos para 2 (dois)? O que queremos saber quando dividimos em dois? Por que não dividir para 3 ou 5, etc.?
@ el.pescado Este artigo da Wikipedia Parity of Zero está errado. Muitas pessoas foram enganadas por este artigo. Pense antes do Wink.
1
Você está certo. Agora que eu li outras respostas que eu encontrei o seu o mais abrangente :)
el.pescado
@ el.pescado. Obrigado. :) Agora você é o melhor amigo de Zero. (abraço)
1
I execute this code for ODD & EVEN:#include<stdio.h>int main(){int number;
printf("Enter an integer: ");
scanf("%d",&number);if(number %2==0)
printf("%d is even.", number);else
printf("%d is odd.", number);}
Você só precisa olhar para o último dígito em qualquer número para ver se é par ou ímpar. Assinado, sem sinal, positivo, negativo - são todos iguais no que diz respeito a isso. Portanto, isso deve funcionar o tempo todo: -
void tellMeIfItIsAnOddNumberPlease(int iToTest){int iLastDigit;
iLastDigit = iToTest -(iToTest /10*10);if(iLastDigit %2==0){
printf("The number %d is even!\n", iToTest);}else{
printf("The number %d is odd!\n", iToTest);}}
A chave aqui está na terceira linha do código, o operador de divisão executa uma divisão inteira, para que o resultado esteja faltando a parte da fração do resultado. Por exemplo, 222/10 dará 22 como resultado. Em seguida, multiplique novamente por 10 e você terá 220. Subtraia isso do 222 original e você terminará com 2, que por mágica é o mesmo número que o último dígito no número original. ;-) Os parênteses estão aí para nos lembrar da ordem em que o cálculo é feito. Primeiro faça a divisão e a multiplicação, depois subtraia o resultado do número original. Poderíamos deixá-los de fora, pois a prioridade é mais alta para divisão e multiplicação do que para subtração, mas isso nos dá um código "mais legível".
Poderíamos tornar tudo completamente ilegível, se quiséssemos. Não faria nenhuma diferença para um compilador moderno:
printf("%d%s\n",iToTest,0==(iToTest-iToTest/10*10)%2?" is even":" is odd");
Mas isso tornaria o código muito mais difícil de manter no futuro. Imagine que você gostaria de alterar o texto dos números ímpares para "não é par". Então alguém mais tarde quer descobrir quais alterações você fez e executar um svn diff ou similar ...
Se você não está preocupado com a portabilidade, mas mais com a velocidade, pode dar uma olhada no bit menos significativo. Se esse bit estiver definido como 1, é um número ímpar; se for 0, é um número par. Em um pequeno sistema endian, como a arquitetura x86 da Intel, seria algo como isto: -
O que exatamente há de errado em apenas ir ao iToTest% 2 == 0? Você está desperdiçando uma divisão extraindo o último dígito, portanto o seu é duas vezes mais lento que o necessário.
Freespace
@ espaço: eu desperdiço mais do que isso, não é? :-) Uma multiplicação e uma subtração também. Mas o que é mais eficiente entre as duas soluções que não ouso dizer. Nunca reivindiquei que essa seja a solução mais rápida, muito pelo contrário, se você ler a primeira linha do meu post novamente.
Tooony
@Tooony, ah, meu chapéu de humor caiu. É formly volta agora: D Desculpe por isso :)
freespace
0
Se você quer ser eficiente, use operadores bit a bit ( x & 1), mas se quiser ser legível, use o módulo 2 ( x % 2)
-1: se você quiser ser eficiente, use qualquer um deles. Se você quiser que seja portátil, use %. Se você quiser que seja legível, use %. Hmmm, eu vejo um padrão aqui.
Thomas Eding
@ Trinithis, não há padrão e esta solução é muito melhor que a sua.
Subs
0
Verificar par ou ímpar é uma tarefa simples.
Sabemos que qualquer número exatamente divisível por 2 é o número par mais ímpar.
Só precisamos verificar a divisibilidade de qualquer número e, para verificar a divisibilidade, usamos o %operador
O código verifica o último bit do número inteiro se é 1 em binário
Explicação
Binary:Decimal-------------------0000=00001=10010=20011=30100=40101=50110=60111=71000=81001=9
and so on...
Observe que o bit mais à direita é sempre 1 para números ímpares .
os & bit a bit E operador verifica o bit mais à direita em nosso retorno linha Se for 1
Pense nisso como verdadeiro e falso
Quando comparamos n com 1, o que significa 0001em binário (o número de zeros não importa).
então vamos apenas imaginar que temos o número inteiro n com tamanho de 1 byte.
Seria representado por dígitos de 8 bits / 8 binários.
Se o int n era 7 e o comparamos com 1 , é como
7(1-byte int)|00000111&1(1-byte int)|00000001********************************************Result| F F F F F F F T
Qual F significa falso e T como verdadeiro.
Ele compara apenas o bit mais à direita se ambos forem verdadeiros. Então, automagicamente 7 & 1é T rue.
E se eu quiser verificar a parte antes da direita?
Simplesmente mude n & 1para n & 2qual 2 representa 0010em Binário e assim por diante.
Sugiro usar notação hexadecimal se você é iniciante em operações bit a bit return n & 1;>> return n & 0x01;.
Respostas:
Use o operador modulo (%) para verificar se há um restante ao dividir por 2:
Algumas pessoas criticaram minha resposta acima afirmando que usar x & 1 é "mais rápido" ou "mais eficiente". Não acredito que seja esse o caso.
Por curiosidade, criei dois programas triviais de casos de teste:
Em seguida, compilei isso com o gcc 4.1.3 em uma de minhas máquinas 5 vezes diferentes:
Examinei a saída de montagem de cada compilação (usando gcc-S) e descobri que, em cada caso, a saída para and.c e modulo.c eram idênticas (ambos usavam a instrução andl $ 1,% eax). Duvido que esse seja um "novo" recurso, e suspeito que remonta a versões antigas. Também duvido que qualquer compilador não arcano moderno (comercializado nos últimos 20 anos), de código aberto ou comercial, não tenha essa otimização. Eu testaria em outros compiladores, mas não tenho nenhum disponível no momento.
Se alguém mais gostaria de testar outros compiladores e / ou destinos de plataforma e obtiver um resultado diferente, eu ficaria muito interessado em saber.
Finalmente, a versão do módulo é garantida pelo padrão para trabalhar se o número inteiro é positivo, negativo ou zero, independentemente da representação da implementação de números inteiros assinados. A versão bit a bit e não é. Sim, eu sei que o complemento de dois é onipresente, então isso não é realmente um problema.
fonte
Vocês são muito eficientes. O que você realmente quer é:
Repita para
isEven
.Claro, isso não funciona para números negativos. Mas com brilho vem o sacrifício ...
fonte
Use aritmética de bits:
Isso é mais rápido do que usar divisão ou módulo.
fonte
[Modo piada = "ativado"]
[Modo brincadeira = "desativado"]
EDIT: Adicionado valores confusos para a enumeração.
fonte
Em resposta ao ffpf - eu tive exatamente o mesmo argumento com um colega anos atrás, e a resposta é não , ele não funciona com números negativos.
O padrão C estipula que números negativos podem ser representados de três maneiras:
Verificando assim:
funcionará no complemento de 2 e na representação de sinal e magnitude, mas não no complemento de 1.
No entanto, acredito que o seguinte funcionará para todos os casos:
Agradeço ao ffpf por apontar que a caixa de texto estava comendo tudo depois do meu personagem menor que o!
fonte
Uma boa é:
Observe que esse método usa recursão de cauda envolvendo duas funções. Ele pode ser implementado com eficiência (transformado em um tipo de loop de tempo / até) se o seu compilador suportar recursão de cauda como um compilador Scheme. Nesse caso, a pilha não deve transbordar!
fonte
Um número é par se, quando dividido por dois, o restante for 0. Um número será ímpar se, quando dividido por 2, o restante for 1.
Métodos são ótimos!
fonte
fonte
Eu diria que basta dividi-lo por 2 e se houver um 0 restante, é par; caso contrário, é estranho.
Usar o módulo (%) facilita isso.
por exemplo. 4% 2 = 0 portanto 4 é par 5% 2 = 1 portanto 5 é ímpar
fonte
Mais uma solução para o problema
(as crianças podem votar)
fonte
Eu criaria uma tabela de paridades (0 se 1 igual a ímpar) dos números inteiros (para que se pudesse fazer uma pesquisa: D), mas o gcc não me permite fazer matrizes de tamanhos iguais:
Então, vamos recorrer à definição matemática de par e ímpar.
Um número inteiro n é uniforme se existir um número inteiro k tal que n = 2k.
Um número inteiro n é ímpar se existir um número k tal que n = 2k + 1.
Aqui está o código para isso:
Let C-inteiros denotam os possíveis valores de
int
em uma dada compilação C. (Observe que C-inteiros é um subconjunto dos inteiros.)Agora, pode-se preocupar que, para um dado n em C-inteiros, o número inteiro correspondente k possa não existir em C-inteiros. Mas com uma pequena prova, pode-se mostrar que para todos os números inteiros n, | n | <= | 2n | (*), onde | n | é "n se n for positivo e -n caso contrário". Em outras palavras, para todos os n em números inteiros, pelo menos um dos itens a seguir é válido (exatamente os casos (1 e 2) ou os casos (3 e 4), de fato, mas não vou provar aqui):
Caso 1: n <= 2n.
Caso 2: -n <= -2n.
Caso 3: -n <= 2n.
Caso 4: n <= -2n.
Agora pegue 2k = n. (Tal ak existe se n for par, mas eu não vou provar aqui. Se n for par, o loop in
even
não retornará mais cedo, portanto não importa.) Mas isso implica k <n se n não 0 por (*) e o fato (novamente não provado aqui) de que para todo m, z em números inteiros 2m = z implica z diferente de m dado m não é 0. No caso n é 0, 2 * 0 = 0 então 0 é o mesmo que terminamos (se n = 0 então 0 está em números inteiros C porque n está em números inteiros C na funçãoeven
, portanto, k = 0 está em números inteiros C). Assim, tal ak em C-inteiros existe para n em C-inteiros se n for par.Um argumento semelhante mostra que se n é ímpar, existe ak em números inteiros C de modo que n = 2k + 1.
Portanto, as funções
even
eodd
apresentadas aqui funcionarão corretamente para todos os C-inteiros.fonte
i % 2
é muito menor e provavelmente mais eficiente.%2
funciona para todos os números inteiros.fonte
typedef
ou#define
ou algo assim.Aqui está uma resposta em Java:
fonte
Tente o seguinte:
return (((a>>1)<<1) == a)
Exemplo:
fonte
Lendo essa discussão bastante divertida, lembrei que tinha uma função sensível ao tempo no mundo real que testava números ímpares e pares dentro do loop principal. É uma função de potência inteira, publicada em outro lugar no StackOverflow, da seguinte maneira. Os benchmarks foram bastante surpreendentes. Pelo menos nessa função do mundo real, o módulo é mais lento e significativamente mais. O vencedor, por uma ampla margem, exigindo 67% do tempo do módulo, é uma abordagem ou (|) , e não pode ser encontrado em nenhum outro lugar nesta página.
Para 300 milhões de loops, os tempos de referência são os seguintes.
3.962 the | e abordagem de máscara
4.851 a abordagem
5.850 a abordagem%
Para pessoas que pensam que a teoria, ou uma listagem em linguagem assembly, resolve argumentos como esses, isso deve ser um conto de advertência. Há mais coisas no céu e na terra, Horácio, do que se sonha em sua filosofia.
fonte
unsigned x
comox = x >> 1;
é o comportamento definido pela implementação quandox < 0
. Não está claro por quex
eOrMask
diferem em tipo. Simples o suficiente para reescrever usando umwhile(x)
teste.% 2
caso usando o bit a bit&
. Acabei de testar isso e os resultados são os mesmos (VS2015, a versão é compilada com todas as otimizações, x86 e x64). A resposta aceita também afirma isso para o GCC (escrito em 2008).or
seria mais rápido que umand
é altamente improvável, em qualquer plataforma / compilador. Mesmo se houvesse uma combinação estranha de plataforma / compilador (e você não publicou nem isso nem o código usado para realizar a referência), dependendo de outros compiladores que se comportam da mesma forma, seria uma má aposta de otimização. Então, como eu escrevi, me pergunto em qual plataforma / compilador isso foi testado , porque tenho quase certeza de que não foi medido corretamente.Este é um acompanhamento da discussão com o @RocketRoy sobre sua resposta , mas pode ser útil para quem quiser comparar esses resultados.
tl; dr Pelo que tenho visto, a abordagem de Roy (
(0xFFFFFFFF == (x | 0xFFFFFFFE)
) não está totalmente otimizado parax & 1
que amod
abordagem, mas na prática tempos de execução deve vir iguais em todos os casos.Então, primeiro comparei a saída compilada usando o Compiler Explorer :
Funções testadas:
CLang 3.9.0 com -O3:
GCC 6.2 com -O3:
Com o clang, percebemos que todos os três casos são funcionalmente iguais. No entanto, a abordagem de Roy não é otimizada no GCC, portanto, YMMV.
É semelhante ao Visual Studio; inspecionando a desmontagem do Release x64 (VS2015) para essas três funções, pude ver que a parte de comparação é igual para os casos "mod" e "e" e "e um pouco maior para o caso" ou "de Roy:
No entanto, após executar uma referência real para comparar essas três opções (modificação simples, bit a bit ou bit a bit e), os resultados foram completamente iguais (novamente, Visual Studio 2005 x86 / x64, versão Build, sem depurador anexado).
A montagem de liberação usa as
test
instruções paraand
emod
casos, enquanto o caso de Roy usa acmp eax,0FFFFFFFFh
abordagem, mas é fortemente desenrolada e otimizada para que não haja diferença na prática.Meus resultados após 20 execuções (i7 3610QM, plano de energia do Windows 10 definido como Alto desempenho):
A diferença entre essas opções é menor que 0,3%; portanto, é óbvio que a montagem é igual em todos os casos.
Aqui está o código, se alguém quiser tentar, com uma ressalva de que eu apenas o testei no Windows (verifique o
#if LINUX
condicional para aget_time
definição e implemente-o, se necessário, retirado desta resposta ).fonte
Eu sei que isso é apenas açúcar sintático e aplicável apenas em .net, mas e o método de extensão ...
Agora você pode fazer o seguinte
fonte
Na "categoria criativa, mas confusa", ofereço:
Uma variante desse tema específica do Microsoft C ++:
fonte
O método bit a bit depende da representação interna do número inteiro. O módulo funcionará em qualquer lugar onde houver um operador de módulo. Por exemplo, alguns sistemas realmente usam os bits de baixo nível para marcação (como linguagens dinâmicas), para que o x & 1 bruto não funcione nesse caso.
fonte
IsOdd (int x) {return true; }
Prova de correção - considere o conjunto de todos os números inteiros positivos e suponha que exista um conjunto de números inteiros não vazios que não sejam ímpares. Como números inteiros positivos são bem ordenados, haverá um número menor e não ímpar, o que por si só é bastante ímpar, tão claramente que esse número não pode estar no conjunto. Portanto, este conjunto não pode estar vazio. Repita para números inteiros negativos, exceto procure o maior número não ímpar.
fonte
Portátil:
Não portável:
fonte
Como algumas pessoas postaram, existem várias maneiras de fazer isso. De acordo com este site , o caminho mais rápido é o operador de módulo:
No entanto, aqui está outro código que foi marcado pelo autor mais lento que a operação de módulo comum acima:
Quantas pessoas conheciam o método Math.System.DivRem ou por que o usariam?
fonte
feito.
fonte
Para dar mais detalhes sobre o método do operador bit a bit para aqueles que não fizeram muita álgebra booleana durante nossos estudos, aqui está uma explicação. Provavelmente não é de muita utilidade para o OP, mas eu queria deixar claro por que o NUMBER & 1 funciona.
Observe que, como alguém respondeu acima, a maneira como os números negativos são representados pode interromper o funcionamento desse método. De fato, ele também pode quebrar o método do operador de módulo, pois cada idioma pode diferir na maneira como lida com operandos negativos.
No entanto, se você souber que NUMBER sempre será positivo, isso funcionará bem.
Como Tooony acima mencionou, apenas o último dígito em binário (e negação) é importante.
Uma lógica AND booleana dita que ambas as entradas devem ser 1 (ou alta tensão) para que 1 seja retornado.
1 e 0 = 0.
0 e 1 = 0.
0 e 0 = 0.
1 e 1 = 1.
Se você representa qualquer número como binário (usei uma representação de 8 bits aqui), os números ímpares têm 1 no final, os números pares têm 0.
Por exemplo:
1 = 00000001
2 = 00000010
3 = 00000011
4 = 00000100
Se você pegar qualquer número e usar AND bit a bit (& em java) por 1, retornará 00000001, = 1, o que significa que o número é ímpar. Ou 00000000 = 0, significando que o número é par.
Por exemplo
É estranho?
1 & 1 =
00000001 &
00000001 =
00000001 <- Ímpar
2 & 1 =
00000010 &
00000001 =
00000000 <- Par
54 & 1 =
00000001 &
00110110 =
00000000 <- Par
É por isso que isso funciona:
Desculpe se isso é redundante.
fonte
Paridade de número zero | zero http://tinyurl.com/oexhr3k
Sequência de código Python.
fonte
fonte
Por uma questão de discussão ...
Você só precisa olhar para o último dígito em qualquer número para ver se é par ou ímpar. Assinado, sem sinal, positivo, negativo - são todos iguais no que diz respeito a isso. Portanto, isso deve funcionar o tempo todo: -
A chave aqui está na terceira linha do código, o operador de divisão executa uma divisão inteira, para que o resultado esteja faltando a parte da fração do resultado. Por exemplo, 222/10 dará 22 como resultado. Em seguida, multiplique novamente por 10 e você terá 220. Subtraia isso do 222 original e você terminará com 2, que por mágica é o mesmo número que o último dígito no número original. ;-) Os parênteses estão aí para nos lembrar da ordem em que o cálculo é feito. Primeiro faça a divisão e a multiplicação, depois subtraia o resultado do número original. Poderíamos deixá-los de fora, pois a prioridade é mais alta para divisão e multiplicação do que para subtração, mas isso nos dá um código "mais legível".
Poderíamos tornar tudo completamente ilegível, se quiséssemos. Não faria nenhuma diferença para um compilador moderno:
Mas isso tornaria o código muito mais difícil de manter no futuro. Imagine que você gostaria de alterar o texto dos números ímpares para "não é par". Então alguém mais tarde quer descobrir quais alterações você fez e executar um svn diff ou similar ...
Se você não está preocupado com a portabilidade, mas mais com a velocidade, pode dar uma olhada no bit menos significativo. Se esse bit estiver definido como 1, é um número ímpar; se for 0, é um número par. Em um pequeno sistema endian, como a arquitetura x86 da Intel, seria algo como isto: -
fonte
Se você quer ser eficiente, use operadores bit a bit (
x & 1
), mas se quiser ser legível, use o módulo 2 (x % 2
)fonte
%
. Se você quiser que seja legível, use%
. Hmmm, eu vejo um padrão aqui.Verificar par ou ímpar é uma tarefa simples.
Só precisamos verificar a divisibilidade de qualquer número e, para verificar a divisibilidade, usamos o
%
operadorVerificando ímpares usando se mais
Programa C para verificar par ou ímpar usando se mais
Usando o operador Condicional / Ternário
Programa C para verificar par ou ímpar usando o operador condicional .
Usando o operador Bitwise
fonte
+ 66% mais rápido>
!(i%2) / i%2 == 0
O código verifica o último bit do número inteiro se é 1 em binário
Explicação
os & bit a bit E operador verifica o bit mais à direita em nosso retorno linha Se for 1
Pense nisso como verdadeiro e falso
Quando comparamos n com 1, o que significa
0001
em binário (o número de zeros não importa).então vamos apenas imaginar que temos o número inteiro n com tamanho de 1 byte.
Seria representado por dígitos de 8 bits / 8 binários.
Se o int n era 7 e o comparamos com 1 , é como
Qual F significa falso e T como verdadeiro.
E se eu quiser verificar a parte antes da direita?
Simplesmente mude
n & 1
paran & 2
qual 2 representa0010
em Binário e assim por diante.Sugiro usar notação hexadecimal se você é iniciante em operações bit a bit
return n & 1;
>>return n & 0x01;
.fonte