Compare dois números inteiros em C ou C ++ sem operadores de comparação


12

Produza o programa mais curto que recebe dois números inteiros assinados como entrada (por meio de stdin ou como argumentos) e exibe 3 saídas diferentes, dependendo de o primeiro número ser (1) maior que, (2) menor que ou (3) igual ao segundo número.

A pegada

Você não pode usar nenhum dos seguintes itens no seu programa:

  • Os operadores de comparação padrão: <, >, <=, >=, ==, !=.
  • Qualquer arquivo de biblioteca para além de conio, stdioou iostream.
  • Qualquer caractere ASCII não ASCII ou imprimível.

O vencedor

O programa com o menor número de caracteres vence.


Suponho que usar coisas como abs sem incluir o arquivo da biblioteca (porque o compilador sabe mesmo assim) também não é permitido?
Martin Ender

1
@ MartinBüttner sim, isso seria uma suposição correta. :)
grove

5
Por que a restrição de C (++)? Se é porque você deseja que as respostas sejam portáveis, apesar da não portabilidade dos tipos básicos de C, você deve declarar isso. Se for uma restrição arbitrária, você deve estar ciente de que restrições arbitrárias a um idioma não são populares neste site.
Peter Taylor

8
@ PeterTaylor faz parte do desafio. Seria um jogo muito diferente se a pergunta fosse agnóstica. A restrição para C / C ++ altera as estratégias usadas ao abordar o problema. Reconheço a necessidade de perguntas serem abertas à maioria dos idiomas para promover a participação de mais pessoas, mas neste problema em particular, a restrição ao C / C ++ e seus operadores e métodos específicos é parte integrante do desafio.
bosque

1
@EvilTeach yes; se algo não for explicitamente proibido na pergunta, será permitido.
bosque

Respostas:


2

53 bytes

main(a,b){scanf("%d%d",&a,&b);printf("%ld",0l+a-b);}

Somente o primeiro caractere da saída é relevante. As três saídas diferentes são:

  1. '-' se b> a
  2. '0' se a == b
  3. qualquer outro caractere se a> b

Ele funciona para todo o intervalo de entrada de int em todas as plataformas em que sizeof (long)> sizeof (int).

Edit: custa um caractere extra para fazer com que o caso 3 imprima um '+' exclusivamente:

main(a,b){scanf("%d%d",&a,&b);printf("%+ld",0l+a-b);}

6

Talvez eu esteja perdendo algo nas regras, mas ...

81 bytes

main(a,b){scanf("%d%d",&a,&b);long long l=a;l-=b;printf("%lld%d",--l>>63,l>>63);}

Ouputs 00se a > b, -10se a == be -1-1se a < b.


Por mais comum que esse tipo de código seja, C não garante que ele funcione. long longpode ter mais de 64 bits, intpode ser tão grande que você possa estourar, o resultado da alteração correta dos valores negativos é definido pela implementação. Praticamente todas as respostas derivadas de C têm problemas semelhantes.
Yann Vernier

1
@YannVernier: Entendido. Suponho que uma solução 100% infalível seria um monstro, já que a única coisa que poderíamos fazer com segurança (ou seja, sem deslocamento ou transbordamento) é um pouco distorcida e, para fazer isso com segurança, precisaríamos determinar a duração dos operandos usando sizeof.
COTO

6

90 bytes

Se pudermos usar stdio, por que não usar seus recursos de formatação para realizar comparações?

main(a,b){scanf("%d%d",&a,&b);snprintf(&a,2,"%d",b-a);a&=63;putchar(51-!(a-45)-!!(a-48));}

Supõe codificação compatível com ASCII e pouca endianidade.

72 bytes

Os quocientes são arredondados para zero, mas os turnos à direita são (na prática) "arredondados para baixo". Essa é uma oferta morta.

main(a,b){scanf("%d%d",&a,&b);a-=b;putchar(a?a|=1,a/2-(a>>1)?60:62:61);}

65 79 bytes

Outra propriedade distintiva dos números negativos é que eles produzem módulo negativo. Este não depende de representação inteira; funciona até na minha torradeira excesso 127 de 8 bits! Ah, e como podemos usar conio, por que não salvar dois bytes com putch? Agora, se eu pudesse encontrar minha cópia do TurboC ...

main(a,b){scanf("%d%d",&a,&b);long long d=a;d-=b;putch(d?d|=1,d%2-1?60:62:61);}

EDIT : lidar com grandes diferenças, assumindo que long longé maior que int.


Tenho certeza de que você precisa de um delimitador entre os %ds no seu scanfpara analisar inequivocamente dois números inteiros. Boa idéia embora!
Martin Ender

1
@ Martin: Bem, funciona com o GCC, mas não tenho muita certeza se é de boa-fé.
Ell

O que quero dizer é como você distingue entre entradas a = 1, b = 23e a = 12, b = 3. Você não precisaria usar o 123STDIN nos dois casos?
Martin Ender

1
Como eu disse, parece funcionar (com 1 23e 12 3como entradas).
Ell

2
Ohhh, você inclui espaços na entrada. Sim, não estou surpreso que funcione, na verdade.
Martin Ender

5

64 61 caracteres

main(a,b){scanf("%d%d",&a,&b);for(a-=b;a/2;a/=2);putchar(a);}

Imprime os valores dos caracteres -1, 0 e 1 para menos que, igual a ou maior que, respectivamente.

Essa implementação depende de um comportamento indefinido por bser do tipo inte por entradas fora do intervalo INT_MIN / 2para INT_MAX / 2. Nas plataformas em que o excesso de sinal assinado envolve, seja o complemento 2s (basicamente todos eles) ou a magnitude do sinal, ele falhará em 25% dos possíveis pares válidos int. Curiosamente (para mim de qualquer maneira), ele funcionará corretamente em plataformas onde o excesso de sinal assinado satura.


Isso não funcionará se a-bestourar.
Dennis

Infelizmente isso é verdade, mas não consegui pensar em nenhuma maneira independente de plataforma para evitar isso sem operadores de comparação. A pergunta não especifica um intervalo de entradas para as quais os resultados devem ser válidos. Essa resposta é garantida pelo padrão para trabalhar com todas as entradas entre -(2^14)e 2^14 - 1em todas as plataformas compatíveis e provavelmente funcionará para uma faixa substancialmente maior na maioria das plataformas. Todas as outras respostas neste momento fazem suposições sobre tamanho de tipo, tamanhos relativos de tipos ou representação.
Laindir 9/09/14

A pergunta diz dois números inteiros assinados como entrada , então eu diria que tem que funcionar para todos os pares. main(a,b)já é um comportamento indefinido, portanto, nenhuma das respostas é garantida para o trabalho. Não importa a portabilidade.
Dennis

Você está absolutamente certo quanto ao comportamento indefinido, portanto minha implementação realmente não garante nada pelo padrão. Vou adicionar uma nota indicando quais são suas limitações.
Laindir 9/09/14

3

66 102 bytes

main(a,b,c,d,e){scanf("%d %d",&a,&b);e=1<<31;c=a&e;d=b&e;putchar(a-b?c&~d?48:d&~c?49:a-b&e?48:49:50);}

Lê os números inteiros de STDIN e imprime 0(a <b), 1(a> b) ou 2(a == b).

Editar: Agora também deve funcionar para diferenças grandes demais para caber em um número inteiro de 32 bits. Tenho certeza de que o ternário aninhado pode ser reduzido com um pouco mais de mágica.


Corrija-me se estiver errado, mas estou vendo um <0 em seu ternário interno.
overactor

@overactor fixed
Martin Ender

3

52 bytes

Infelizmente, este só funciona para números inteiros positivos, mas achei interessante o conceito de usar operadores puramente aritméticos:

main(a,b){scanf("%d%d",&a,&b);putchar(b%a/b-a%b/a);}

Saídas:

  • Código ASCII 0xFF: a menor que b
  • Código ASCII 0x00: a igual a b
  • Código ASCII 0x01: a maior que b

Se você está procurando apenas números inteiros positivos, putchar(a/b-b/a)é muito menor.
Dennis

@Dennis que produz resultados diferentes, por exemplo, para (50,1) e (51,1). Mas eu fui capaz de diminuir um pouco.
Digital Trauma

1
Sim, não estava pensando corretamente ...
Dennis

3

 59    54 caracteres

54 charcters com um compilador como o gcc que não se opõe a main(x,y):

main(x,y){scanf("%d%d",&x,&y);y-=x;putchar(y>>31|!y);}

59 caracteres caso contrário:

main(){int x,y;scanf("%d%d",&x,&y);y-=x;putchar(y>>31|!y);}

Resultado:

  • Código ASCII 0x00 se x <y
  • Código ASCII 0xFF se x> y
  • Código ASCII 0x01 se x == y

1
Posso garantir, main(x,y)funciona no gcc, portanto, sinta-se à vontade para remover esses 5 bytes da sua contagem de caracteres.
Martin Ender

main (x, y) não funciona no meu gcc. Talvez seja necessária uma opção de compilador. Mas você pode substituir main (x, y) por x; main (y).
Florian F

2

66 bytes

main(a,b){scanf("%d%d",&a,&b);putchar((0l+b-a>>63)-(0l+a-b>>63));}

Imprime o byte 0x00 se a == b, 0x01 se a < be 0xff se a > b.

Como o caractere ASCII não ASCII ou imprimível no programa [my] e se alguma coisa não for explicitamente proibida na pergunta, é permitido que o caractere não imprimível na saída esteja completamente correto.


Minha versão anterior não lidava muito bem com o estouro. Isso funciona no Linux x64, onde longé de 64 bits.
Dennis

2

87 caracteres

main(a,b,c){scanf("%d%d",&a,&b);c=1<<31;a+=c;b+=c;puts(a^b?(unsigned)a/b?">":"<":"=");}

Usando o truque 2 ^ 31 para converter em int sem sinal

Converter a divisão em não assinado para manipular o bit superior como dados, não assinar

Usando ^ para XOR aeb, quando eles são iguais, isso retorna 0

Usando condicionais aninhados (?) Para obter "<", ">" ou "=" para alimentar feeds a puts ()


1

71 bytes

main(x,y,z){scanf("%d%d",&x,&y);putchar((z=x-y)?(z&(z>>31))?50:49:51);}

http://ideone.com/uvXm6c


Seu ideone tem parênteses z=x-ye tenho certeza de que eles são necessários. Você também pode salvar dois caracteres usando 49, 50` e 51diretamente, em vez de adicionar 48.
Martin Ender

Atribuição tem uma prioridade mais baixa do que o operador ternário: en.cppreference.com/w/c/language/operator_precedence
Martin Enders

Seu código acima está faltando um ponto-e-vírgula e falha -2000000000 2000000000, assim como qualquer outra combinação de números inteiros que causam estouro na subtração.
COTO

1

68 caracteres

int main(a,b){scanf("%d%d",&a,&b);putchar(a-b?((unsigned)a-b)>>31:2);}

Coloca o caractere ASCII 1, 2 ou 3 por menos que, maior que ou igual, respectivamente.


1
Isso não funcionará se a-bestourar.
Dennis

1

88 89 bytes

main(a,b){scanf("%d%d",&a,&b);a+=1<<31;b+=1<<31;for(;a&&b;a--)b--;putchar(a?b?48:49:50);}

Isso começa adicionando 1<<31( INT_MIN) a aeb, para que 0 agora corresponda INT_MIN. Em seguida, faz um loop e decrementa a e b a cada loop até que seja 0 e, em seguida, imprime 0, 1 ou 2, dependendo de a, b ou ambos serem 0.

120 119 bytes

main(a,b,c){scanf("%d%d",&a,&b);c=1<<31;a^=c;b^=c;for(c~=c;!c;c/=2)if(a&c^b&c){putchar(a?48:49);return;}putchar(50);}

Não é a solução mais curta, mas pode ser um pouco melhor para o golfista do que eu. (Ou apenas pessoas com mais conhecimento de C do que eu)

A idéia é mascarar cada bit, começando pelo esquerdo e verificando a desigualdade. O resto deve se explicar. Como os números negativos começam com 1 bit, eu primeiro inverto o primeiro bit com a^=1<<31.


Não posso testar minhas soluções no momento, portanto, fique à vontade para apontar erros.
overactor

A primeira solução tem alguns problemas: 1. O ;)sorriso feliz deve ser um );sorriso triste . 2. a&bapenas testa se ae bpossui bits em comum; você precisa &&.
Dennis

@ Dennis, você está certo, obrigado.
overactor 9/09/14

1

Acho que nem vou tentar escrever código curto. O que tentarei é realizar essa comparação de maneira portátil, de acordo com a especificação C99.

int a, b;   // Let's assume these are initialized
int sign_a = a ? ((a|7)^2)%2 + ((a|7)^3)%2 : 0;

O operador modulo preserva o sinal, mas pode muito bem produzir um zero (incluindo zero negativo), portanto, garantimos que temos um valor ímpar e par para verificar (mesmo sem saber se estamos usando o complemento). As operações aritméticas podem estourar, mas bit a bit não e, ao garantir que haja bits definidos e limpos, evitamos converter inadvertidamente nosso número em zero negativo ou em um valor de trap. O fato de que duas operações são necessárias para fazer isso de maneira estranha não deve importar, porque a possível representação de interceptação não causa comportamento indefinido até colocar um valor l. Fazer a operação com o bit 0 alternado garante que obtemos exatamente um restante diferente de zero. Armado com o conhecimento de ambos os sinais, podemos decidir como proceder com a comparação.

char result="\0<<>=<>>\0"[4+3*sign_a+sign_b]
if (!result) {   // signs matching means subtraction won't overflow
  int diff=a-b;
  int sign_diff=diff ? (diff|7^2)%2 + (diff|7^3)%2 : 0;
  result = ">=<"[1-sign_diff];
}

Este método pode ser um dos poucos que permitem extrair o sinal de um número inteiro negativo zero. Resolvemos isso verificando explicitamente zero. Se estivéssemos jogando golfe de verdade, é claro que poderíamos permitir que a comparação de dois zeros também realizasse a subtração.


1

C 80 chars

a,b,c=1<<31;main(){scanf("%d%d",&a,&b);putchar(a^b?(a&c^b&c?a:a-b)&c?60:62:61);}

Imprime '<', '>' ou '=', como deveria.

C 63 chars

Uma nova abordagem:

a;main(b){scanf("%d%d",&a,&b);putchar(50+(0L+a-b>>42)+!(a-b));}

Imprime '1', '2' ou '3'.


1

Em 64 caracteres sem stdio.h

a,b;main(){scanf("%d%d",&a,&b);puts((a-b)>>31?"<":a^b?">":"=");}

imprime '>' se a> b, '<' se a <b, '=' se a == b int overflow for UB. Só não transborde.

// declare a and b as ints
a,b;

// defaults to int
main()
{
  scanf("%d%d",&a,&b);
   /*
    * (a-b)>>31 signbit of a-b
    * a^b a xor b -> 0 if they are equal
    */
  puts(((a-b)>>31) ? "<" : (a^b) ? ">" : "=");
}
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.