C# Operadores de Comparação
Programas tomam decisões o tempo todo: "a nota é suficiente para passar?", "o estoque acabou?", "a senha está certa?". Cada uma dessas perguntas é uma comparação, e a resposta é sempre sim ou não: true (verdadeiro) ou false (falso). Nesta aula você vai conhecer os seis operadores de comparação do C#, ver o que dá para comparar e o que não dá, e aprender as armadilhas de comparar números com vírgula.
- Os seis operadores:
==,!=,>,<,>=e<=. - Que toda comparação produz um
bool, que pode ser guardado numa variável, e por que o console mostraTruecom letra maiúscula. - O que dá para comparar: números,
char,boolestring(só com==e!=). - Por que
0.1 + 0.2 == 0.3dáFalsecomdoubleeTruecomdecimal. - Os erros mais comuns:
=no lugar de==,0 <= nota <= 10e o texto grudado na comparação.
Todos os programas desta aula foram rodados com o .NET 10 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/cs, com o comando dotnet run arquivo.cs (aula Rodar com dotnet run).
A ideia: perguntas de sim ou não
Pense numa balança de dois pratos. Você coloca uma coisa de cada lado, e ela só sabe responder uma pergunta: qual lado pesa mais, ou se estão iguais. Ela não diz "quanto" pesa; diz só "sim" ou "não" para a pergunta que você fez.
Os operadores de comparação são essa balança. Você põe um valor de cada lado do operador, e o C# responde true ou false. São os sinais da matemática da escola, escritos com as teclas do teclado:
| Operador | Pergunta | Na matemática | Exemplo | Resposta |
|---|---|---|---|---|
== | é igual a? | = | 7 == 7 | true |
!= | é diferente de? | ≠ | 7 != 7 | false |
> | é maior que? | > | 7 > 5 | true |
< | é menor que? | < | 7 < 5 | false |
>= | é maior ou igual a? | ≥ | 7 >= 7 | true |
<= | é menor ou igual a? | ≤ | 8 <= 7 | false |
Três detalhes de escrita que pegam todo iniciante:
- Igual é com dois sinais:
==. Um sinal só (=) é a atribuição, "guarde este valor" (aula Operadores de Atribuição). - Diferente é
!=: o!quer dizer "não", então!=se lê "não igual". - Nos operadores de dois símbolos, o
=vem sempre por último:>=e<=, nunca=>nem=<. E não pode haver espaço no meio:> =é erro.
1. A resposta é um bool
A Ana tem 16 anos. Veja as seis perguntas sobre a idade dela:
int idade = 16; Console.WriteLine(idade == 16); Console.WriteLine(idade != 16); Console.WriteLine(idade > 18); Console.WriteLine(idade < 18); Console.WriteLine(idade >= 16); Console.WriteLine(idade <= 15);
$ dotnet run seis.cs True « 16 é igual a 16 False « 16 não é diferente de 16 False « 16 não é maior que 18 True « 16 é menor que 18 True « 16 é maior ou igual a 16 (é igual, e isso basta) False « 16 não é menor ou igual a 15
Cada comparação virou um valor do tipo bool (de boolean, "booleano", em homenagem ao matemático George Boole), o tipo que só tem dois valores (aula char e bool). Repare numa diferença:
- No código, os valores se escrevem com letra minúscula:
trueefalse. - Na tela, o
Console.WriteLinemostraTrueeFalse, com maiúscula. É só o jeito como o .NET transforma umboolem texto. O valor é o mesmo.
Guardar a resposta numa variável
Como a resposta é um valor, ela pode ser guardada numa variável bool, com um nome que diga o que ela significa:
int idade = 17;
bool podeVotar = idade >= 16;
bool podeDirigir = idade >= 18;
Console.WriteLine("Pode votar? " + podeVotar);
Console.WriteLine("Pode dirigir? " + podeDirigir);
Console.WriteLine("Tem 17? " + (idade == 17));
$ dotnet run bool.cs Pode votar? True Pode dirigir? False Tem 17? True
- bool podeVotar = idade >= 16;
- Lida da direita para a esquerda: o C# primeiro calcula
idade >= 16(17 é maior ou igual a 16? sim,true) e depois guarda otrueempodeVotar. O=(um sinal) guarda; o>=pergunta. - "Pode votar? " + podeVotar
- Juntar um texto com um
boolcom+transforma oboolem texto ("True") e cola os dois (aula Strings). - "Tem 17? " + (idade == 17)
- Aqui a comparação está dentro da linha, e os parênteses são obrigatórios. Sem eles, o C# faria o
+primeiro e tentaria comparar um texto com um número. Você vai ver esse erro em Quando dá errado. - nomes como podeVotar
- Variáveis
boolcostumam ter nome de pergunta ou de estado:podeVotar,estaAprovado,temEstoque,ehAdmin. Assim,if (podeVotar)se lê quase como português (aula if e else).
Experimente: mude a nota para 6, 10 e 3 e rode de novo. Depois acrescente uma linha que pergunte se a nota é diferente de zero.
int nota = 7;
Console.WriteLine("Nota: " + nota);
Console.WriteLine("Passou (6 ou mais)? " + (nota >= 6));
Console.WriteLine("Tirou 10? " + (nota == 10));
Console.WriteLine("Ficou abaixo de 5? " + (nota < 5));
2. O que dá para comparar
Os operadores funcionam com vários tipos, mas cada tipo tem suas regras:
Console.WriteLine(5 == 5.0);
Console.WriteLine(7 / 2 == 3.5);
Console.WriteLine('a' < 'b');
Console.WriteLine('Z' < 'a');
Console.WriteLine(true == false);
string nome = "Ana";
Console.WriteLine(nome == "Ana");
Console.WriteLine(nome == "ana");
Console.WriteLine(nome != "Bia");
$ dotnet run tipos.cs True « int com double: o 5 vira 5.0 antes de comparar False « 7 / 2 entre inteiros dá 3, e 3 não é 3.5 True « 'a' vem antes de 'b' True « surpresa: 'Z' (código 90) é menor que 'a' (código 97) False True « mesmo texto False « maiúscula e minúscula contam: "Ana" não é "ana" True
- Números entre si
int,long,doubleedecimalpodem ser comparados entre si. Antes de comparar, o C# converte o menor para o maior (o5vira5.0). Cuidado com a divisão de inteiros:7 / 2é3(aula Operadores Aritméticos).- char
- Cada letra tem um número na tabela Unicode, e é esse número que se compara. Todas as maiúsculas (A = 65 … Z = 90) vêm antes de todas as minúsculas (a = 97 … z = 122). Por isso
'Z' < 'a'étrue. Para ordem alfabética "de verdade", usestring.Compare(aula Strings). - bool
- Só com
==e!=. Não existe "verdadeiro é maior que falso". - string
- Em C#, o
==compara o conteúdo dos textos, letra por letra. (Quem vem do Java estranha: lá,==em texto é uma armadilha. Em C#, não.) Maiúsculas e minúsculas fazem diferença. Os operadores<,>,<=e>=não funcionam comstring: o compilador recusa.
| Tipo | == e != | < > <= >= | Observação |
|---|---|---|---|
int, long, decimal | sim | sim | exatos |
double, float | sim, mas cuidado | sim | veja a próxima seção |
char | sim | sim | compara o código Unicode |
bool | sim | não | erro CS0019 |
string | sim (compara o conteúdo) | não | erro CS0019; use string.Compare |
número com string | não | não | erro CS0019; converta antes (aula Parse e TryParse) |
Missão: no Brasil, pode votar quem tem 16 anos ou mais. O programa diz que alguém de 16 anos não pode. Corrija o operador (não mude a idade) para mostrar Pode votar? True.
Pode votar? True
int idade = 16;
bool podeVotar = idade > 16;
Console.WriteLine("Pode votar? " + podeVotar);
int idade = 16;
bool podeVotar = idade >= 16;
Console.WriteLine("Pode votar? " + podeVotar);
3. Cuidado ao comparar double
O double guarda os números em binário, e muitos números "redondos" para nós, como 0,1, não têm representação exata em binário (aula float, double e decimal). Um errinho minúsculo basta para o == responder false:
double a = 0.1 + 0.2; Console.WriteLine(a == 0.3); Console.WriteLine(a); decimal b = 0.1m + 0.2m; Console.WriteLine(b == 0.3m); Console.WriteLine(Math.Abs(a - 0.3) < 0.000001);
$ dotnet run double.cs False « para o double, 0,1 + 0,2 não é exatamente 0,3 0,30000000000000004 « o erro está lá na 17ª casa True « com decimal, a conta é exata True « a diferença é menor que 0,000001: "praticamente igual"
Repare que o console mostra 0,30000000000000004 com vírgula: a máquina da Ana está em português, e o .NET usa a vírgula decimal do Brasil ao mostrar números. No código, o separador é sempre o ponto (0.1).
Três jeitos de lidar com isso:
- Dinheiro e quantidades exatas: use
decimal(omno fim do número quer dizer money). Com ele,0.1m + 0.2m == 0.3métrue. - Medidas (altura, temperatura, distância): use
doublee compare com tolerância:Math.Abs(a - b) < 0.000001pergunta "a distância entre os dois é menor que um milionésimo?".Math.Absé o valor absoluto, o número sem o sinal (aula Matemática). <e>comdoublesão seguros na maioria dos casos ("a temperatura passou de 38?"). O problema é o==exato.
NaN
0.0 / 0.0 com double não quebra o programa: dá NaN (Not a Number, "não é um número"). E o NaN não é igual a nada, nem a si mesmo: nada == nada é False. Para perguntar se um valor é NaN, use double.IsNaN(nada), que dá True.
4. = não é ==
É o erro mais famoso da programação: escrever um sinal de igual só, quando a intenção era perguntar. Em C#, na maioria dos casos o compilador salva você:
int x = 5;
if (x = 5)
{
Console.WriteLine("cinco");
}
$ dotnet run e3.cs /home/ana/cs/e3.cs(2,5): error CS0029: Não é possível converter implicitamente tipo "int" em "bool" /home/ana/cs/e3.cs(1,5): warning CS0219: A variável "x" é atribuída, mas seu valor nunca é usado Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O if (aula if e else) exige uma resposta bool. Mas x = 5 é uma atribuição, e o resultado de uma atribuição é o valor guardado: o int 5. Daí o erro CS0029: "não dá para transformar um int num bool". O conserto é if (x == 5). (Em C e em C++ esse código compila e roda errado. O C# não deixa.)
Com uma variável bool, porém, a atribuição já é um bool, e o compilador só pode avisar:
bool aprovado = false;
if (aprovado = true)
{
Console.WriteLine("Parabéns!");
}
$ dotnet run e7.cs /home/ana/cs/e7.cs(2,5): warning CS0665: Atribuição em expressão condicional é sempre constante. Deseja usar == em vez de = ? /home/ana/cs/e7.cs(1,6): warning CS0219: A variável "aprovado" é atribuída, mas seu valor nunca é usado Parabéns! « o aluno reprovado ganhou parabéns!
O programa rodou e deu a resposta errada: aprovado = true guardou true na variável, e o if recebeu esse true. O aviso CS0665 pergunta exatamente: "você queria usar == em vez de =?". Avisos não impedem o programa de rodar, mas quase sempre apontam um erro de verdade: leia todos (aula Avisos do Compilador). Com um bool, nem precisa comparar: escreva só if (aprovado).
Formas diferentes de fazer a mesma pergunta
| Esta forma… | …é igual a esta | Qual usar |
|---|---|---|
idade >= 18 | idade > 17 | Iguais só para inteiros. Use a que tem o número da regra: "maior de idade é 18 ou mais" → >= 18. Com double, 17.5 > 17 é true, e as duas deixam de ser iguais. |
a < b | b > a | A que se lê mais naturalmente: preco < 100 ("o preço é menor que 100") em vez de 100 > preco. |
aprovado == true | aprovado | A forma curta. O bool já é a resposta. |
aprovado == false | !aprovado | Os dois aparecem bastante. O ! ("não") é assunto da próxima aula, Operadores Lógicos. |
nome == "Ana" | nome.Equals("Ana") | ==. O Equals com opções (como ignorar maiúsculas) aparece em Strings. |
Quando dá errado
error CS0019: O operador ">=" não pode ser aplicado a operandos dos tipos "string" e "int"
int idade = 16;
Console.WriteLine("Pode votar? " + idade >= 16);
$ dotnet run e1.cs /home/ana/cs/e1.cs(2,19): error CS0019: O operador ">=" não pode ser aplicado a operandos dos tipos "string" e "int" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: o + é feito antes do >= (aula Precedência). O C# juntou "Pode votar? " + idade, que deu o texto "Pode votar? 16", e depois tentou perguntar se esse texto é maior ou igual a 16. Texto com número não se compara. Em inglês: Operator '>=' cannot be applied to operands of type 'string' and 'int'.
Como consertar: parênteses em volta da comparação: "Pode votar? " + (idade >= 16).
error CS0019: O operador "<=" não pode ser aplicado a operandos dos tipos "bool" e "int"
int nota = 7; Console.WriteLine(0 <= nota <= 10);
$ dotnet run e2.cs /home/ana/cs/e2.cs(2,19): error CS0019: O operador "<=" não pode ser aplicado a operandos dos tipos "bool" e "int" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: na matemática, 0 ≤ nota ≤ 10 é uma frase só. No C#, são duas operações: primeiro 0 <= nota, que dá true; depois true <= 10, e um bool não se compara com um número.
Como consertar: faça as duas perguntas completas e junte com && ("e"): nota >= 0 && nota <= 10. É o assunto da próxima aula, Operadores Lógicos.
error CS0029: Não é possível converter implicitamente tipo "int" em "bool"
O que significa: você escreveu if (x = 5), com um sinal de igual só. Isso é uma atribuição, que dá um int, e o if precisa de um bool.
Como consertar: if (x == 5).
warning CS0665: Atribuição em expressão condicional é sempre constante. Deseja usar == em vez de = ?
O que significa: mesmo erro de cima, mas com uma variável bool: o programa compila, roda e sempre entra no if.
Como consertar: if (aprovado) (ou if (aprovado == true)).
error CS1525: Termo de expressão inválido "<"
int x = 5; Console.WriteLine(x =< 10);
$ dotnet run e4.cs /home/ana/cs/e4.cs(2,22): error CS1525: Termo de expressão inválido "<" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: =< não existe. O C# leu um = (atribuição) e depois encontrou um < solto, onde esperava um valor. A coluna 22 aponta o <.
Como consertar: o = vem por último: x <= 10.
error CS0019: O operador "<" não pode ser aplicado a operandos dos tipos "string" e "string"
string a = "Ana"; string b = "Bia"; Console.WriteLine(a < b);
$ dotnet run e5.cs /home/ana/cs/e5.cs(3,19): error CS0019: O operador "<" não pode ser aplicado a operandos dos tipos "string" e "string" Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: textos não têm "maior" e "menor" com < e > no C#.
Como consertar: para saber a ordem alfabética, use string.Compare(a, b), que dá um número negativo quando a vem antes (aula Strings).
error CS0019: O operador "==" não pode ser aplicado a operandos dos tipos "int" e "string" e warning CS1718
int idade = 20; string texto = "20"; Console.WriteLine(idade == texto); Console.WriteLine(idade == idade);
$ dotnet run e6.cs /home/ana/cs/e6.cs(3,19): error CS0019: O operador "==" não pode ser aplicado a operandos dos tipos "int" e "string" /home/ana/cs/e6.cs(4,19): warning CS1718: Comparação feita com a mesma variável. Você pretendia comparar com outro elemento? Ocorreu uma falha no build. Corrija os erros de build e execute novamente.
O que significa: o número 20 e o texto "20" são coisas diferentes para o C#: um é quantidade, o outro são dois caracteres. A linha 4 compila, mas o aviso CS1718 lembra que comparar uma variável com ela mesma é sempre true: provavelmente você digitou o nome errado.
Como consertar: transforme o texto em número antes (int.Parse(texto), aula Parse e TryParse) e confira os nomes das variáveis.
Referência
| Operador | Nome | a = 7, b = 5 | Funciona com |
|---|---|---|---|
a == b | igual a | false | todos os tipos (texto compara o conteúdo) |
a != b | diferente de | true | todos os tipos |
a > b | maior que | true | números e char |
a < b | menor que | false | números e char |
a >= b | maior ou igual a | true | números e char |
a <= b | menor ou igual a | false | números e char |
Math.Abs(x - y) < 0.000001 | "quase igual" | — | double e float |
double.IsNaN(x) | é NaN? | — | double e float |
O resultado de todos é um bool: true ou false no código, True ou False na tela.
Exercícios
1. Diferente
Complete com o operador "diferente de":
2. Aprovação
Aprova quem tira 6 ou mais. Complete:
3. Os parênteses
O que falta para esta linha compilar? Reescreva a parte depois do +:
4. O que Console.WriteLine(10 > 3); mostra?
5. O que Console.WriteLine('Z' < 'a'); mostra?
6. Com string nome = "Ana";, quanto vale nome == "Ana" em C#?
7. Por que 0 <= nota <= 10 não compila?
Missão final: o troco da lojinha
Missão: o caixa da lojinha da Ana soma duas moedas (R$ 0,10 e R$ 0,20) e confere se deu o preço da bala, R$ 0,30. Com double, o programa diz que não deu. Troque os tipos por decimal (lembre do m no fim de cada número) para mostrar Troco certo? True.
Troco certo? True
double pago = 0.1 + 0.2;
double preco = 0.3;
Console.WriteLine("Troco certo? " + (pago == preco));
decimal pago = 0.1m + 0.2m;
decimal preco = 0.3m;
Console.WriteLine("Troco certo? " + (pago == preco));
Depois de cumprir a missão, tente tirar o m do 0.3m e leia o erro do compilador: error CS0664: Literal do tipo double não pode ser convertido implicitamente no tipo "decimal"; use um sufixo "M" para criar um literal desse tipo. Sem o m, 0.3 é um double, e o C# não transforma double em decimal sozinho (aula float, double e decimal).
Resumo
- Seis operadores:
==,!=,>,<,>=,<=. Igualdade tem dois sinais; nos compostos, o=vem por último. - Toda comparação dá um
bool, que pode ser guardado:bool aprovado = nota >= 6;. Na tela ele aparece comoTrueouFalse. - Dentro de um texto com
+, ponha a comparação entre parênteses:"Passou? " + (nota >= 6). - Números se comparam entre si (
5 == 5.0étrue);charcompara códigos Unicode;boolsó com==e!=. string:==e!=comparam o conteúdo;<e>não existem (CS0019).double:==exato é perigoso. Para dinheiro,decimal; para medidas, tolerância comMath.Abs.=no lugar de==dáCS0029(com números) ou o avisoCS0665(combool).- "Entre dois valores" são duas comparações:
nota >= 0 && nota <= 10.