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.

Você vai aprender
  • 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á inf com double.
  • 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.
OperadorNomeExemploResultado
+Soma (adição)17 + 522
-Subtração17 - 512
*Multiplicação17 * 585
/Divisão17 / 53 (com inteiros!)
%Resto da divisão (módulo)17 % 52

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+b funciona 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 é um int, 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
  1. 135 / 60 = 2: cabem 2 horas inteiras (120 minutos).
  2. 135 % 60 = 15: sobram 15 minutos (135 − 120).
  3. 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 136 traduz: 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.

A regra de ouro

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 resultado é 0 (ou menor do que devia), sem nenhum aviso

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

OperadorCom intCom doubleCuidado
a + b7 + 2 = 97.5 + 2 = 9.5Números muito grandes estouram o int (Inteiros).
a - b7 - 2 = 57.5 - 2 = 5.5
a * b7 * 2 = 147.5 * 2 = 15
a / b7 / 2 = 3 (corta)7.0 / 2 = 3.5Inteiro por zero: o programa quebra (SIGFPE). Double por zero: inf/nan.
a % b7 % 2 = 1Não existe (use std::fmod)O sinal do resultado é o do a: -7 % 2 = −1.
-a-7-7.5Troca 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):

int ultimo = numero ;

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 um double na 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, use n % 2 != 0.
  • % só funciona com inteiros; com double, use std::fmod.
  • Inteiro dividido por zero: o programa quebra (SIGFPE, código de saída 136 = 128 + 8). double dividido por zero: inf, -inf ou nan.
  • * / % antes de + -; mesma prioridade, da esquerda para a direita. Na dúvida, parênteses.
  • ^ não é potência: use std::pow.