C++ Operadores Aritméticos
Computador vem de "computar", calcular. Fazer contas é o trabalho mais básico de qualquer programa: somar o carrinho de compras, dividir a conta do restaurante, converter minutos em horas. Os símbolos que fazem essas contas se chamam operadores aritméticos. Quatro deles você já conhece da escola; o quinto, o %, é novidade e muito útil. Nesta aula você vai usar todos, ver as duas divisões do C++ e descobrir o que acontece quando alguém divide por zero.
- Os cinco operadores:
+,-,*,/e%. - A diferença entre divisão inteira (
7 / 2= 3) e real (7 / 2.0= 3.5). - O resto da divisão (
%) e para que ele serve: par ou ímpar, horas e minutos, reais e centavos. - O que
%faz com números negativos. - O que acontece ao dividir por zero: o programa quebra com inteiros e dá
infcomdouble. - A ordem em que as contas são feitas, e por que o
^não é potência.
Todos os programas desta aula foram compilados com o g++ 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/cpp, com o comando padrão do guia: g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa.
A ideia: a calculadora com uma tecla a mais
Os operadores do C++ são as teclas de uma calculadora, com duas diferenças:
- A multiplicação é o asterisco
*(o teclado não tem ×), e a divisão é a barra/(o teclado não tem ÷). - Existe uma tecla a mais, o
%, que dá o resto de uma divisão. É o "sobrou" da continha armada que você fazia na escola: 17 balas para 5 crianças dá 3 para cada e sobram 2.
| Operador | Nome | Exemplo | Resultado |
|---|---|---|---|
+ | Soma (adição) | 17 + 5 | 22 |
- | Subtração | 17 - 5 | 12 |
* | Multiplicação | 17 * 5 | 85 |
/ | Divisão | 17 / 5 | 3 (com inteiros!) |
% | Resto da divisão (módulo) | 17 % 5 | 2 |
1. Os cinco operadores
#include <iostream>
int main() {
int a = 17;
int b = 5;
std::cout << a + b << '\n';
std::cout << a - b << '\n';
std::cout << a * b << '\n';
std::cout << a / b << '\n';
std::cout << a % b << '\n';
}
$ g++ -std=c++23 -Wall -Wextra contas.cpp -o contas $ ./contas 22 12 85 3 « 17 / 5: cabem 3 inteiros (3 × 5 = 15) 2 « 17 % 5: sobram 2 (17 - 15)
- a + b
- Uma expressão: valores ligados por um operador. O C++ calcula a expressão e o resultado é usado no lugar dela (aqui, mostrado pelo
cout). - a e b
- Os operandos: os valores em que o operador trabalha. Podem ser variáveis, números escritos direto (
17 + 5) ou outras expressões (a * 2 + 1). - os espaços
- São opcionais:
a+bfunciona igual. Com espaços fica mais fácil de ler, e é o estilo deste guia.
Uma expressão não muda as variáveis: depois de a + b, o a continua 17. Para guardar um resultado, use uma variável: int total = a + b;. Para mudar a própria variável (a = a + b, ou o atalho a += b), veja Operadores de Atribuição.
O menos sozinho: trocar o sinal
O - também funciona com um operando só, na frente de um valor: ele troca o sinal. O nome técnico é operador unário ("de um operando"; os outros são binários, de dois):
#include <iostream>
int main() {
int saldo = 50;
int divida = -saldo;
std::cout << divida << '\n';
std::cout << -divida << '\n';
std::cout << 10 - -3 << '\n';
double metade = 1 / 2;
std::cout << metade << '\n';
}
$ g++ -std=c++23 -Wall -Wextra sinais.cpp -o sinais $ ./sinais -50 50 « menos com menos dá mais 13 « 10 - (-3) 0 « a última linha é a próxima seção!
2. A divisão: inteira ou real
O / do C++ faz duas divisões diferentes, dependendo do tipo dos números:
int / int→ divisão inteira. O resultado é umint, e a parte fracionária é jogada fora (não é arredondada).17 / 5= 3,1 / 2= 0,7 / 2= 3.- Se um dos lados é
double→ divisão real.7 / 2.0= 3.5,1.0 / 2= 0.5.
É por isso que double metade = 1 / 2; deu 0: a conta 1 / 2 foi feita entre inteiros (resultado 0) e só depois o 0 foi guardado no double. A variável ser double não muda a conta. Esse assunto, com o static_cast<double> para resolver, é explicado em detalhe na aula Conversão de Tipos.
Com números negativos, a divisão inteira corta em direção ao zero: -7 / 2 é −3,5, que vira −3 (e não −4).
A divisão inteira não é um defeito: muitas vezes é exatamente o que você quer. Quantas caixas de 6 ovos dá para encher com 20 ovos? 20 / 6 = 3. Ninguém quer "3,33 caixas".
3. O resto: %
O % (lê-se "módulo" ou "resto") dá o que sobra de uma divisão inteira. Ele e o / trabalham juntos: o / diz quantas vezes cabe, o % diz quanto sobrou.
O uso mais comum é quebrar uma quantidade em unidades. 135 minutos são quantas horas e quantos minutos? E 1234 centavos são quantos reais?
#include <iostream>
int main() {
int minutos = 135;
int horas = minutos / 60;
int resto = minutos % 60;
std::cout << minutos << " minutos = " << horas << "h" << resto << "min\n";
int centavos = 1234;
std::cout << "R$ " << centavos / 100 << "," << centavos % 100 << '\n';
}
$ g++ -std=c++23 -Wall -Wextra tempo.cpp -o tempo $ ./tempo 135 minutos = 2h15min R$ 12,34
135 / 60= 2: cabem 2 horas inteiras (120 minutos).135 % 60= 15: sobram 15 minutos (135 − 120).1234 / 100= 12 reais;1234 % 100= 34 centavos.
(Com 1205 centavos, este programa mostraria R$ 12,5, porque o 5 não ganha um zero na frente. Para formatar com dois dígitos, veja Formatar com iomanip.)
Par ou ímpar
Outro uso clássico: um número é par se o resto da divisão por 2 é zero. 8 % 2 = 0 (par), 7 % 2 = 1 (ímpar). Da mesma forma, n % 10 dá o último algarismo de n, e n % 3 == 0 diz se n é múltiplo de 3.
Experimente: troque os 200 ovos por outros números e veja quantas caixas de 12 ficam cheias e quantos ovos sobram. Depois troque o tamanho da caixa para 6.
#include <iostream>
int main() {
int ovos = 200;
int por_caixa = 12;
std::cout << "Caixas cheias: " << ovos / por_caixa << '\n';
std::cout << "Ovos soltos: " << ovos % por_caixa << '\n';
}
% com números negativos
Aqui o C++ pode surpreender quem vem da matemática. A regra é: o resultado do % tem o mesmo sinal do número da esquerda (o que está sendo dividido). Isso acontece porque a divisão inteira corta em direção ao zero, e o resto é o que "falta" para voltar ao número original.
#include <iostream>
int main() {
std::cout << 7 % 3 << '\n';
std::cout << -7 % 3 << '\n';
std::cout << 7 % -3 << '\n';
std::cout << -7 % -3 << '\n';
std::cout << -7 / 2 << '\n';
}
$ g++ -std=c++23 -Wall -Wextra resto.cpp -o resto $ ./resto 1 « 7 = 3 × 2 + 1 -1 « -7 = 3 × (-2) + (-1): o sinal vem do -7 1 « 7 = (-3) × (-2) + 1: o sinal vem do 7 -1 -3 « -3,5 cortado em direção ao zero
Na prática, isso morde no teste de ímpar. Muita gente escreve "ímpar é quando n % 2 == 1". Para negativos, não funciona:
#include <iostream>
int main() {
std::cout << 3 % 2 << '\n';
std::cout << -3 % 2 << '\n';
std::cout << (-3 % 2 == 1) << '\n';
std::cout << (-3 % 2 != 0) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra impar.cpp -o impar $ ./impar 1 -1 « o resto de -3 por 2 é -1, não 1 0 « "-3 é ímpar?" pelo teste == 1: falso (errado!) 1 « "-3 é ímpar?" pelo teste != 0: verdadeiro (certo)
O 1 e o 0 são o jeito de o cout mostrar verdadeiro e falso (veja Booleanos e Operadores de Comparação). A lição: para saber se é ímpar, teste n % 2 != 0, que funciona para positivos e negativos.
% só funciona com inteiros
$ g++ -std=c++23 -Wall -Wextra restod.cpp -o restod
restod.cpp: In function ‘int main()’:
restod.cpp:5:20: error: invalid operands of types ‘double’ and ‘int’ to binary ‘operator%’
5 | std::cout << x % 2 << '\n';
| ~ ^ ~
| | |
| | int
| double
"Operandos inválidos dos tipos double e int para o operator% binário": a variável x era double (7.5). Para o resto de números com vírgula existe a função std::fmod, de <cmath>: std::fmod(7.5, 2) dá 1.5 (veja Matemática (cmath)).
4. Dividir por zero
Na matemática, dividir por zero "não existe". No C++, o que acontece depende do tipo.
Com inteiros: o programa quebra
#include <iostream>
int main() {
int pizzas = 8;
int pessoas = 0;
std::cout << "Dividindo...\n";
std::cout << pizzas / pessoas << '\n';
std::cout << "Fim\n";
}
$ g++ -std=c++23 -Wall -Wextra zero.cpp -o zero $ ./zero Dividindo... Exceção de ponto flutuante (imagem do núcleo gravada) ./zero $ echo $? 136
O g++ compilou sem aviso (ele não sabe, ao compilar, que pessoas vai valer 0). Ao rodar, o programa morreu na linha da divisão: o Fim nunca apareceu. Vamos entender cada pedaço:
- Exceção de ponto flutuante
- A mensagem é do Bash, não do seu programa: ele avisa que o programa foi morto pelo sinal SIGFPE (floating-point exception). O nome é histórico e engana: a conta era com inteiros, e mesmo assim o sinal se chama "ponto flutuante". Num sistema em inglês, a mensagem é
Floating point exception (core dumped). - (imagem do núcleo gravada)
- Em inglês, core dumped: o sistema pode ter salvo uma "fotografia" da memória do programa para investigar depois (veja Depurar com o GDB).
- 136
- O código de saída. Quando um programa é morto por um sinal, o Bash informa 128 + número do sinal. O SIGFPE é o sinal 8: 128 + 8 = 136. O comando
kill -l 136traduz:FPE.
Se o zero estiver escrito direto na conta, o g++ percebe e avisa, mas compila mesmo assim:
$ g++ -std=c++23 -Wall -Wextra zero2.cpp -o zero2
zero2.cpp: In function ‘int main()’:
zero2.cpp:4:20: warning: division by zero [-Wdiv-by-zero]
4 | std::cout << 8 / 0 << '\n';
| ~~^~~
$ ./zero2
Exceção de ponto flutuante (imagem do núcleo gravada) ./zero2
$ echo $?
136
Dividir um inteiro por zero é comportamento indefinido: a regra do C++ não diz o que acontece, e quebrar com SIGFPE é só o que acontece no Linux com processador Intel/AMD. Também vale para %: 8 % 0 quebra igual. No editor do guia, que roda o programa em WebAssembly, a mensagem é outra, mas o programa também para. A aula Comportamento Indefinido explica por que isso é tão perigoso.
Antes de dividir por um valor que veio de fora (do teclado, de um arquivo, de uma conta), confira se ele é zero. Você vai aprender a fazer essa conferência com if em if e else, e um truque com && em Operadores Lógicos.
Com double: infinito
Os números de ponto flutuante seguem uma norma internacional (IEEE 754) que tem valores especiais para isso. O programa não quebra:
#include <iostream>
int main() {
double pizzas = 8;
double pessoas = 0;
std::cout << pizzas / pessoas << '\n';
std::cout << -pizzas / pessoas << '\n';
std::cout << pessoas / pessoas << '\n';
}
$ g++ -std=c++23 -Wall -Wextra zerod.cpp -o zerod $ ./zerod inf « infinito positivo -inf « infinito negativo -nan « "not a number", não é um número: 0 / 0 não tem resposta
Não quebrar não quer dizer que está certo: inf e nan se espalham pelas contas seguintes (inf + 1 é inf, qualquer conta com nan dá nan) e estragam o resultado em silêncio. O sinal de menos no -nan é um detalhe da forma como o processador guarda esse valor; em outros sistemas pode aparecer só nan. Veja mais em float e double.
5. A ordem das contas
Como na matemática da escola, multiplicação, divisão e resto vêm antes de soma e subtração. E, quando os operadores têm a mesma prioridade, a conta é feita da esquerda para a direita:
#include <iostream>
int main() {
std::cout << 2 + 3 * 4 << '\n';
std::cout << (2 + 3) * 4 << '\n';
std::cout << 10 - 4 - 3 << '\n';
std::cout << 100 / 10 * 2 << '\n';
std::cout << 7 / 2 * 2 << '\n';
std::cout << 7 * 2 / 2 << '\n';
std::cout << -3 * -2 << '\n';
}
$ g++ -std=c++23 -Wall -Wextra ordem.cpp -o ordem $ ./ordem 14 « 3 * 4 primeiro (12), depois 2 + 12 20 « os parênteses mandam: 5 * 4 3 « (10 - 4) - 3, da esquerda para a direita 20 « (100 / 10) * 2, e não 100 / 20 6 « (7 / 2) * 2 = 3 * 2: a divisão inteira perdeu o 0,5 7 « (7 * 2) / 2 = 14 / 2: mesma conta em outra ordem, outro resultado 6 « o menos unário vem antes de tudo
As linhas 5 e 6 mostram por que a ordem importa ainda mais com inteiros: na matemática, 7 ÷ 2 × 2 e 7 × 2 ÷ 2 são iguais; em C++ com int, não. O caso clássico é a média de duas notas:
#include <iostream>
int main() {
int nota1 = 8;
int nota2 = 9;
std::cout << nota1 + nota2 / 2 << '\n';
std::cout << (nota1 + nota2) / 2 << '\n';
std::cout << (nota1 + nota2) / 2.0 << '\n';
}
$ g++ -std=c++23 -Wall -Wextra media.cpp -o media $ ./media 12 « 8 + (9 / 2) = 8 + 4: a divisão foi feita antes da soma 8 « parênteses certos, mas divisão inteira: 17 / 2 = 8 8.5 « parênteses certos e divisão real
Dois erros diferentes numa conta só. A tabela completa de prioridades (inclusive com comparações e lógicos) está na aula Precedência. A regra prática: na dúvida, coloque parênteses. Eles não custam nada e deixam a intenção clara.
O ^ não é potência
Em muitas calculadoras, 2^3 é "2 elevado a 3". Em C++, não: o ^ é um operador de bits chamado "ou exclusivo" (XOR), que não tem nada a ver com potência. O g++ 15 até reconhece o engano:
$ cat potencia.cpp
#include <cmath>
#include <iostream>
int main() {
std::cout << (2 ^ 3) << '\n';
std::cout << 2 * 2 * 2 << '\n';
std::cout << std::pow(2, 3) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra potencia.cpp -o potencia
potencia.cpp: In function ‘int main()’:
potencia.cpp:5:21: warning: result of ‘2^3’ is 1; did you mean ‘1 << 3’ (8)? [-Wxor-used-as-pow]
5 | std::cout << (2 ^ 3) << '\n';
| ^
| -
| 1 <<
potencia.cpp:5:19: note: you can silence this warning by using a hexadecimal constant (0x2 rather than 2)
5 | std::cout << (2 ^ 3) << '\n';
| ^
| 0x2
$ ./potencia
1 « 2 ^ 3 é 1 (XOR), não 8
8
8
"O resultado de 2^3 é 1; você quis dizer 1 << 3 (8)?" O C++ não tem operador de potência. Para potências pequenas, multiplique (x * x para o quadrado); para as outras, use std::pow de <cmath> (aula Matemática).
Quando dá errado
Exceção de ponto flutuante (imagem do núcleo gravada) e código 136
O que aconteceu: uma divisão (/) ou resto (%) com inteiros teve zero do lado direito. O processador recusou a conta e o sistema matou o programa com o sinal SIGFPE (8). O código de saída é 128 + 8 = 136. Tudo o que viria depois daquela linha não rodou.
Como resolver: descubra qual divisão tinha zero (o GDB mostra a linha exata) e confira o divisor antes de dividir. Se você pegou o valor do teclado, lembre que uma leitura que falha também dá 0 (veja Entrada com cin).
O que aconteceu: divisão inteira. 1 / 2 é 0; 17 / 2 é 8. Guardar num double não ajuda, porque a conta já foi feita.
Como resolver: faça um dos lados ser double antes da conta: 1.0 / 2 ou static_cast<double>(soma) / n (veja Conversão de Tipos).
error: invalid operands of types ‘double’ and ‘int’ to binary ‘operator%’
O que aconteceu: você usou % com um double. O % só existe para inteiros.
Como resolver: se os valores deveriam ser inteiros, mude o tipo para int. Se precisam ter vírgula, use std::fmod(a, b).
warning: result of ‘2^3’ is 1; did you mean ‘1 << 3’ (8)?
O que aconteceu: você usou ^ achando que era potência.
Como resolver: std::pow(2, 3) ou 2 * 2 * 2.
Referência
| Operador | Com int | Com double | Cuidado |
|---|---|---|---|
a + b | 7 + 2 = 9 | 7.5 + 2 = 9.5 | Números muito grandes estouram o int (Inteiros). |
a - b | 7 - 2 = 5 | 7.5 - 2 = 5.5 | |
a * b | 7 * 2 = 14 | 7.5 * 2 = 15 | |
a / b | 7 / 2 = 3 (corta) | 7.0 / 2 = 3.5 | Inteiro por zero: o programa quebra (SIGFPE). Double por zero: inf/nan. |
a % b | 7 % 2 = 1 | Não existe (use std::fmod) | O sinal do resultado é o do a: -7 % 2 = −1. |
-a | -7 | -7.5 | Troca o sinal. |
Ordem: - unário → * / % → + -; na mesma prioridade, da esquerda para a direita. Parênteses mudam a ordem.
Exercícios
1. Quanto sobra?
Qual é o resultado de 23 % 4?
2. Divisão inteira
Qual é o resultado de 23 / 4 (dois int)?
3. A ordem
Qual é o resultado de 10 - 2 * 3 + 1?
4. Último algarismo
Complete para ultimo receber o último algarismo de numero (de 2026, o 6):
5. Quanto é -9 % 4 em C++?
6. int a = 10; int b = 0; O que acontece em std::cout << a / b;?
Missão final: o cronômetro
Missão: transforme 3725 segundos em horas, minutos e segundos, usando / e % (uma hora tem 3600 segundos, um minuto tem 60). A saída deve ser:
3725 segundos = 1h 2min 5s
#include <iostream>
int main() {
int total = 3725;
int horas = 0; // troque o 0 pela conta certa
int minutos = 0; // idem
int segundos = 0; // idem
std::cout << total << " segundos = " << horas << "h " << minutos << "min " << segundos << "s\n";
}
#include <iostream>
int main() {
int total = 3725;
int horas = total / 3600;
int minutos = total % 3600 / 60;
int segundos = total % 60;
std::cout << total << " segundos = " << horas << "h " << minutos << "min " << segundos << "s\n";
}
Resumo
+ - * /são as quatro operações;%dá o resto da divisão inteira.int / inté divisão inteira: corta a parte fracionária (7 / 2= 3,-7 / 2= −3). Com umdoublena conta, a divisão é real./e%juntos quebram quantidades: minutos em horas e minutos, centavos em reais e centavos.- O resto tem o sinal do número da esquerda:
-7 % 3= −1. Para testar ímpar, usen % 2 != 0. %só funciona com inteiros; comdouble, usestd::fmod.- Inteiro dividido por zero: o programa quebra (SIGFPE, código de saída 136 = 128 + 8).
doubledividido por zero:inf,-infounan. * / %antes de+ -; mesma prioridade, da esquerda para a direita. Na dúvida, parênteses.^não é potência: usestd::pow.