C Matemática (math.h)
Os operadores + - * / % (Operadores Aritméticos) fazem as quatro operações. Para raiz quadrada, potência, arredondamento ou seno, o C tem uma caixa de funções prontas: a biblioteca de matemática, que você abre com #include <math.h>. Nesta aula você vai usar as funções mais comuns, entender por que o gcc às vezes exige uma opção a mais (-lm) e ver o que acontece quando a conta não tem resposta, como a raiz de um número negativo.
- Calcular raiz quadrada (
sqrt) e potência (pow). - Por que o gcc mostra
referência não definida para "sqrt"e como o-lmresolve. - A diferença entre
abs(inteiros) efabs(números com vírgula). - Arredondar de quatro jeitos:
round,floor,ceiletrunc. - O resto com vírgula (
fmod), a distância entre dois pontos (hypot) e o π. - Seno e cosseno trabalham em radianos, não em graus.
- O que são
naneinf, e como testá-los comisnaneisinf.
Todos os programas foram compilados com o gcc 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/c, com o comando padrão do guia, gcc -std=c23 -Wall -Wextra arquivo.c -o programa, mais o -lm no fim, que a seção 1 explica.
A ideia: a calculadora científica
A calculadora comum da Ana faz as quatro operações. Para a lição de geometria, ela pega a calculadora científica, que tem as teclas √, xʸ, sin, cos e π. Em C é parecido:
| Na calculadora | Em C |
|---|---|
| As quatro operações, sempre à mão | Os operadores + - * /, que fazem parte da linguagem |
| Pegar a calculadora científica na gaveta | #include <math.h> no topo do arquivo |
Apertar a tecla √ e digitar 49 | Chamar a função: sqrt(49.0) |
As funções de math.h recebem e devolvem double (float e double). Você pode passar um int: o C converte sozinho (Conversão de Tipos). Mas o resultado é sempre um double, e por isso é mostrado com %f, nunca com %d.
1. Raiz quadrada: sqrt e o -lm
A Ana quer cercar um canteiro quadrado de 49 m². Qual é o tamanho de cada lado? É a raiz quadrada da área: sqrt ("square root", raiz quadrada).
#include <stdio.h>
#include <math.h>
int main(void) {
double area = 49.0;
double lado = sqrt(area);
printf("Um quadrado de %.1f m² tem lado de %.1f m\n", area, lado);
printf("Raiz de 2: %.6f\n", sqrt(2.0));
return 0;
}
- #include <math.h>
- Traz as declarações das funções de matemática: o compilador fica sabendo que
sqrtexiste, que recebe umdoublee devolve umdouble. - double lado = sqrt(area);
- Chama a função com o valor de
areae guarda o resultado, 7.0. - sqrt(2.0)
- A raiz de 2 não é exata (1,41421356…). O
%.6fmostra seis casas.
Compilando com o comando de sempre, vem uma surpresa:
$ gcc -std=c23 -Wall -Wextra raiz.c -o raiz /usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/ccPawk0J.o: na função "main": raiz.c:(.text+0x23): referência não definida para "sqrt" collect2: error: ld returned 1 exit status $ gcc -std=c23 -Wall -Wextra raiz.c -o raiz -lm $ ./raiz Um quadrado de 49.0 m² tem lado de 7.0 m Raiz de 2: 1.414214
O erro não veio do compilador, e sim do ligador (ld), a etapa final que junta o seu programa com as bibliotecas (Como o C Funciona). Referência não definida para "sqrt" (em inglês, undefined reference to `sqrt') quer dizer: "o seu código usa sqrt, mas eu não achei o corpo dessa função em lugar nenhum".
O #include <math.h> só apresenta a função ao compilador. O código dela mora num arquivo à parte, a biblioteca de matemática (libm, "lib" de biblioteca e "m" de matemática). Por uma tradição antiga do Unix, o gcc no Linux junta sozinho a biblioteca principal do C (a do printf), mas não a de matemática. A opção -lm pede: "ligue (-l) a biblioteca m".
-lm vai no fim
O ligador lê o comando da esquerda para a direita. Se a biblioteca vem antes do arquivo que a usa, ele ainda não sabe que vai precisar dela e a descarta. O mesmo erro volta:
$ gcc -std=c23 -Wall -Wextra -lm raiz.c -o raiz /usr/bin/x86_64-linux-gnu-ld.bfd: /tmp/cckch8md.o: na função "main": raiz.c:(.text+0x23): referência não definida para "sqrt" collect2: error: ld returned 1 exit status
Regra: os arquivos .c primeiro, as bibliotecas (-lm) depois.
Por que às vezes funciona sem -lm?
Você pode encontrar programas com sqrt que compilam sem o -lm. Este, por exemplo:
#include <stdio.h>
#include <math.h>
int main(void) {
printf("Raiz de 49: %.1f\n", sqrt(49.0));
return 0;
}
$ gcc -std=c23 -Wall -Wextra constante.c -o constante « sem -lm, e compilou $ ./constante Raiz de 49: 7.0
Aqui o número está escrito no código (49.0), e o gcc é esperto: ele mesmo calcula a raiz durante a compilação e escreve 7.0 no programa. Ninguém precisa chamar a sqrt de verdade, e o ligador não procura a biblioteca. O mesmo acontece com o fabs (seção 3), que o gcc troca por uma instrução do processador. Com uma variável, como no raiz.c, a conta só pode ser feita quando o programa roda, e aí a biblioteca é necessária. Para não ter de pensar nisso: usou math.h, ponha -lm.
O editor já junta a biblioteca de matemática sozinho: as caixas desta aula funcionam sem -lm. No Linux, com o gcc, ele é necessário.
2. Potência: pow
O C não tem operador de potência. O ^ existe, mas é outra coisa: o "ou exclusivo" de Operadores de Bits. O engano é tão comum que o gcc 15 avisa:
$ cat xor.c
#include <stdio.h>
int main(void) {
printf("%d\n", 2 ^ 10);
return 0;
}
$ gcc -std=c23 -Wall -Wextra xor.c -o xor
xor.c: In function ‘main’:
xor.c:4:22: warning: result of ‘2^10’ is 8; did you mean ‘1 << 10’ (1024)? [-Wxor-used-as-pow]
4 | printf("%d\n", 2 ^ 10);
| ^
| -
| 1 <<
xor.c:4:20: note: you can silence this warning by using a hexadecimal constant (0x2 rather than 2)
4 | printf("%d\n", 2 ^ 10);
| ^
| 0x2
$ ./xor
8
"O resultado de 2^10 é 8; você quis dizer 1 << 10 (1024)?" (o << também é de Operadores de Bits, e só serve para potências de 2). Para elevar um número qualquer a outro, use pow(base, expoente) ("power", potência):
#include <stdio.h>
#include <math.h>
int main(void) {
printf("2 elevado a 10 = %.0f\n", pow(2, 10));
printf("1.5 ao quadrado = %.2f\n", pow(1.5, 2));
printf("raiz cúbica de 27 = %.1f\n", pow(27, 1.0 / 3));
double guardado = 1000.0;
double depois = guardado * pow(1.01, 12);
printf("R$ %.2f a 1%% ao mês, depois de 12 meses: R$ %.2f\n", guardado, depois);
return 0;
}
- pow(2, 10)
- 210 = 1024. Os
int2 e 10 viramdoublena entrada; o resultado é odouble1024.0, mostrado com%.0f(zero casas). - pow(27, 1.0 / 3)
- Elevar a 1/3 é tirar a raiz cúbica. Repare no
1.0:1 / 3seria divisão inteira e daria 0 (float e double), epow(27, 0)é 1. - guardado * pow(1.01, 12)
- Juros compostos: 1% ao mês é multiplicar por 1,01 a cada mês; doze meses são 1,0112.
- 1%%
- Dentro do
printf,%%mostra um%(Formatos do printf).
$ gcc -std=c23 -Wall -Wextra potencia.c -o potencia -lm $ ./potencia 2 elevado a 10 = 1024 1.5 ao quadrado = 2.25 raiz cúbica de 27 = 3.0 R$ 1000.00 a 1% ao mês, depois de 12 meses: R$ 1126.83
O resultado é double
O engano mais comum com pow é mostrar o resultado com %d:
#include <stdio.h>
#include <math.h>
int main(void) {
printf("%d\n", pow(2, 10));
return 0;
}
$ gcc -std=c23 -Wall -Wextra powd.c -o powd -lm
powd.c: In function ‘main’:
powd.c:5:14: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat=]
5 | printf("%d\n", pow(2, 10));
| ~^ ~~~~~~~~~~
| | |
| int double
| %f
$ ./powd
1293164760
"O formato %d espera um int, mas o argumento é double". O gcc até sugere o %f. Ignorando o aviso, o programa mostra lixo: um double é guardado de um jeito totalmente diferente de um int, e o printf leu o lugar errado. No editor, o mesmo programa mostra 0. Se você quer um inteiro, converta com um cast: int casas = (int) pow(2, 10);.
x * x é mais simples e mais rápido que pow(x, 2), e funciona com int sem conversão. Deixe o pow para expoentes grandes ou com vírgula.
Experimente: mude os juros para 2% ao mês (1.02) e o prazo para 24 meses. Depois tente calcular a raiz quadrada de 2 com pow (que expoente dá a raiz quadrada?) e compare com sqrt(2.0).
#include <stdio.h>
#include <math.h>
int main(void) {
double guardado = 1000.0;
double depois = guardado * pow(1.01, 12);
printf("Depois de 12 meses: R$ %.2f\n", depois);
printf("sqrt(2.0) = %.6f\n", sqrt(2.0));
return 0;
}
3. Valor absoluto: abs e fabs
O valor absoluto é o número sem o sinal: o absoluto de −35 é 35, e o de 35 também. Serve para medir distâncias e diferenças ("errou o palpite por quanto?"). O C tem uma função para cada tipo:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(void) {
int saldo = -35;
double temperatura = -2.5;
printf("abs(%d) = %d\n", saldo, abs(saldo));
printf("fabs(%.1f) = %.1f\n", temperatura, fabs(temperatura));
return 0;
}
$ gcc -std=c23 -Wall -Wextra absoluto.c -o absoluto -lm $ ./absoluto abs(-35) = 35 fabs(-2.5) = 2.5
- abs
- "Absolute", absoluto, para
int. Mora no<stdlib.h>, não nomath.h. Paralongelong long, existemlabsellabs. - fabs
- "Floating absolute", absoluto de ponto flutuante, para
double. Mora no<math.h>.
Trocar uma pela outra é um erro silencioso: abs com um double joga fora a parte depois da vírgula. O -Wextra avisa:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
double temperatura = -2.5;
printf("%d\n", abs(temperatura));
return 0;
}
$ gcc -std=c23 -Wall -Wextra abserrado.c -o abserrado
abserrado.c: In function ‘main’:
abserrado.c:6:20: warning: using integer absolute value function ‘abs’ when argument is of floating-point type ‘double’ [-Wabsolute-value]
6 | printf("%d\n", abs(temperatura));
| ^~~
$ ./abserrado
2
"Usando a função de valor absoluto de inteiros, abs, com um argumento de ponto flutuante". O −2.5 virou −2 na entrada, e o resultado foi 2, não 2.5. O Clang do editor dá o mesmo aviso e ainda sugere: note: use function 'fabs' instead ("use a função fabs").
4. Arredondar: round, floor, ceil e trunc
"Arredondar" pode querer dizer quatro coisas diferentes. Veja as quatro funções com os mesmos números:
#include <stdio.h>
#include <math.h>
int main(void) {
double valores[] = {2.4, 2.5, 2.6, -2.4, -2.5, -2.6};
printf("valor round floor ceil trunc\n");
for (int i = 0; i < 6; i++) {
double x = valores[i];
printf("%5.1f %5.1f %5.1f %5.1f %5.1f\n",
x, round(x), floor(x), ceil(x), trunc(x));
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra arredondar.c -o arredondar -lm $ ./arredondar valor round floor ceil trunc 2.4 2.0 2.0 3.0 2.0 2.5 3.0 2.0 3.0 2.0 2.6 3.0 2.0 3.0 2.0 -2.4 -2.0 -3.0 -2.0 -2.0 -2.5 -3.0 -3.0 -2.0 -2.0 -2.6 -3.0 -3.0 -2.0 -2.0
| Função | Nome | O que faz | 2.5 | −2.5 |
|---|---|---|---|---|
round | "arredondar" | Para o inteiro mais próximo; o meio (,5) vai para longe do zero | 3 | −3 |
floor | "chão" | Sempre para baixo (o inteiro menor ou igual) | 2 | −3 |
ceil | "ceiling", teto | Sempre para cima (o inteiro maior ou igual) | 3 | −2 |
trunc | "truncar", cortar | Corta a parte depois da vírgula (vai em direção ao zero) | 2 | −2 |
Repare nos negativos: floor(-2.4) é −3, porque −3 é menor que −2.4. Já o trunc faz o mesmo que um cast (int): só corta. Todas devolvem double (por isso o 3.0). Para receber um inteiro, existe o lround, que devolve long (aula Conversão de Tipos).
Quando usar cada um: as caixas de ovos
A Ana tem 40 ovos e cada caixa leva 12. Quantas caixas ela precisa? 40 / 12 = 3,33…, e 3 caixas não bastam: sobram ovos. Aqui o certo é o ceil, sempre para cima. Mas cuidado com a divisão:
#include <stdio.h>
#include <math.h>
int main(void) {
int ovos = 40;
int por_caixa = 12;
int caixas = (int) ceil((double) ovos / por_caixa);
int errado = (int) ceil(ovos / por_caixa);
printf("Caixas necessárias: %d\n", caixas);
printf("Com divisão inteira: %d\n", errado);
return 0;
}
$ gcc -std=c23 -Wall -Wextra caixas.c -o caixas -lm $ ./caixas Caixas necessárias: 4 Com divisão inteira: 3
Na segunda conta, ovos / por_caixa é uma divisão de dois int: dá 3, sem vírgula, antes de o ceil receber o valor. Não há o que arredondar. O (double) na primeira conta faz a divisão ser com vírgula (3,33…), e o ceil leva a 4. O (int) da frente converte o resultado (4.0) para guardar num int.
Arredondar com duas casas decimais
As funções arredondam para o inteiro. Para arredondar a média 7,4567 em duas casas, multiplique por 100, arredonde e divida de volta:
#include <stdio.h>
#include <math.h>
int main(void) {
double media = 7.4567;
double arredondada = round(media * 100) / 100;
printf("Média guardada: %.4f\n", media);
printf("Arredondada: %.4f\n", arredondada);
printf("Só na tela: %.2f\n", media);
return 0;
}
$ gcc -std=c23 -Wall -Wextra casas.c -o casas -lm $ ./casas Média guardada: 7.4567 Arredondada: 7.4600 Só na tela: 7.46
7,4567 × 100 = 745,67; arredondado, 746; dividido por 100, 7,46. Se você só quer mostrar com duas casas, o %.2f já arredonda na tela, sem mudar o valor guardado. Use o round quando o valor arredondado for usado em outras contas.
5. Resto com vírgula: fmod
O % só funciona com inteiros. Com double, o gcc recusa:
$ gcc -std=c23 -Wall -Wextra restoerr.c -o restoerr
restoerr.c: In function ‘main’:
restoerr.c:5:27: error: invalid operands to binary % (have ‘double’ and ‘double’)
5 | printf("%.1f\n", fita % 3.0);
| ^
"Operandos inválidos para o % (recebeu double e double)". Para o resto com vírgula, use fmod ("floating modulo"). A Ana tem 10 m de fita e corta pedaços de 3 m:
#include <stdio.h>
#include <math.h>
int main(void) {
double fita = 10.0;
double pedaco = 3.0;
printf("Pedaços inteiros: %.0f\n", floor(fita / pedaco));
printf("Sobra: %.1f m\n", fmod(fita, pedaco));
printf("Sobra de 7.5 / 2: %.1f\n", fmod(7.5, 2.0));
return 0;
}
$ gcc -std=c23 -Wall -Wextra resto.c -o resto -lm $ ./resto Pedaços inteiros: 3 Sobra: 1.0 m Sobra de 7.5 / 2: 1.5
Três pedaços de 3 m usam 9 m e sobra 1 m. E 7,5 = 3 × 2 + 1,5. No editor, a mensagem do Clang para o % com double é invalid operands to binary expression ('double' and 'double').
6. Distância entre dois pontos: sqrt e hypot
No mapa do bairro, a casa da Ana fica no ponto (1, 2) e a escola no ponto (4, 6), em quarteirões. Em linha reta, qual é a distância? É o teorema de Pitágoras: a raiz de (diferença em x)² + (diferença em y)².
#include <stdio.h>
#include <math.h>
int main(void) {
double x1 = 1.0, y1 = 2.0;
double x2 = 4.0, y2 = 6.0;
double dx = x2 - x1;
double dy = y2 - y1;
printf("Com sqrt: %.2f\n", sqrt(dx * dx + dy * dy));
printf("Com hypot: %.2f\n", hypot(dx, dy));
return 0;
}
$ gcc -std=c23 -Wall -Wextra distancia.c -o distancia -lm $ ./distancia Com sqrt: 5.00 Com hypot: 5.00
dx é 3 e dy é 4: 3² + 4² = 9 + 16 = 25, e a raiz de 25 é 5. A função hypot ("hypotenuse", hipotenusa) faz a mesma conta de uma vez e, com números muito grandes ou muito pequenos, perde menos precisão.
Missão: a pracinha fica no ponto (2, 3) e a sorveteria no ponto (14, 8). Complete o cálculo da distância em linha reta, com sqrt ou hypot.
Distância: 13.00
#include <stdio.h>
#include <math.h>
int main(void) {
double x1 = 2.0, y1 = 3.0;
double x2 = 14.0, y2 = 8.0;
double dx = x2 - x1;
double dy = y2 - y1;
double d = dx + dy; // troque pela conta certa
printf("Distância: %.2f\n", d);
return 0;
}
#include <stdio.h>
#include <math.h>
int main(void) {
double x1 = 2.0, y1 = 3.0;
double x2 = 14.0, y2 = 8.0;
double dx = x2 - x1;
double dy = y2 - y1;
double d = sqrt(dx * dx + dy * dy);
printf("Distância: %.2f\n", d);
return 0;
}
7. O número π
Muita gente escreve M_PI para o π, e muitos tutoriais usam. Com o comando padrão do guia, o gcc não reconhece:
#include <stdio.h>
#include <math.h>
int main(void) {
double raio = 2.0;
printf("Área: %.2f\n", M_PI * raio * raio);
return 0;
}
$ gcc -std=c23 -Wall -Wextra pi.c -o pi -lm
pi.c: In function ‘main’:
pi.c:6:28: error: ‘M_PI’ undeclared (first use in this function)
6 | printf("Área: %.2f\n", M_PI * raio * raio);
| ^~~~
pi.c:6:28: note: each undeclared identifier is reported only once for each function it appears in
$ gcc -Wall -Wextra pi.c -o pi -lm « sem o -std=c23
$ ./pi
Área: 12.57
O M_PI não faz parte do C padrão: é um extra do Unix. Com -std=c23 (C padrão, sem extras), o math.h não o define. Sem o -std, o gcc usa o "C23 com extras do GNU" e ele aparece. No editor, o Clang também recusa: use of undeclared identifier 'M_PI'. Para um programa que compila em qualquer lugar, defina o seu π com constexpr (Constantes):
#include <stdio.h>
#include <math.h>
constexpr double PI = 3.14159265358979323846;
int main(void) {
double raio = 3.0;
printf("Área do canteiro: %.2f m²\n", PI * raio * raio);
printf("Comprimento da borda: %.2f m\n", 2 * PI * raio);
printf("acos(-1) = %.15f\n", acos(-1.0));
return 0;
}
$ gcc -std=c23 -Wall -Wextra pi2.c -o pi2 -lm $ ./pi2 Área do canteiro: 28.27 m² Comprimento da borda: 18.85 m acos(-1) = 3.141592653589793
- constexpr double PI = 3.14159265358979323846;
- Uma constante de verdade C23, com mais casas do que um
doubleconsegue guardar (ele guarda umas 16). Em C antigo, escreva#define PI 3.14159265358979323846. - acos(-1.0)
- Outro jeito clássico de obter o π: o arco cujo cosseno é −1 mede π radianos (meia volta). Mostra que o π calculado bate com o escrito.
8. Seno e cosseno: em radianos
As funções sin (seno), cos (cosseno) e tan (tangente) recebem o ângulo em radianos, não em graus. Uma volta inteira tem 360 graus, ou 2π radianos. Para converter: radianos = graus × π / 180.
#include <stdio.h>
#include <math.h>
constexpr double PI = 3.14159265358979323846;
int main(void) {
double graus = 30.0;
double rad = graus * PI / 180.0;
printf("sin(30 graus) = %.4f\n", sin(rad));
printf("cos(60 graus) = %.4f\n", cos(60.0 * PI / 180.0));
printf("sin(30) sem converter = %.4f\n", sin(30.0));
return 0;
}
$ gcc -std=c23 -Wall -Wextra trig.c -o trig -lm $ ./trig sin(30 graus) = 0.5000 cos(60 graus) = 0.5000 sin(30) sem converter = -0.9880 « o seno de 30 radianos, não de 30 graus
O seno de 30 graus é 0,5, como na escola. Sem converter, sin(30.0) calcula o seno de 30 radianos (quase 5 voltas), e o resultado não tem nada a ver. O compilador não avisa: para ele, 30.0 é só um número.
9. Quando a conta não tem resposta: nan e inf
Não existe raiz quadrada (real) de um número negativo, nem logaritmo de zero. Em vez de travar, as funções devolvem valores especiais do double:
#include <stdio.h>
#include <math.h>
int main(void) {
double x = -4.0;
double zero = 0.0;
double r = sqrt(x);
printf("sqrt(-4) = %f\n", r);
printf("log(0) = %f\n", log(zero));
printf("1 / 0.0 = %f\n", 1.0 / zero);
if (isnan(r)) {
printf("r não é um número (NaN)\n");
}
if (isinf(log(zero))) {
printf("log(0) é infinito\n");
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra nan.c -o nan -lm $ ./nan sqrt(-4) = -nan log(0) = -inf 1 / 0.0 = inf r não é um número (NaN) log(0) é infinito
- nan
- "Not a number", não é um número: o resultado de uma conta impossível. Qualquer conta com um
nandánan, e ele "contamina" o resto do programa. (O sinal de menos em-nannão tem significado prático.) - inf
- "Infinity", infinito.
log(0)é menos infinito;1.0 / 0.0é mais infinito. Comdouble, dividir por zero não derruba o programa (comint, derruba: veja float e double). - isnan(r), isinf(x)
- Perguntam "é
nan?" e "é infinito?". Não dá para testar comr == NAN: umnannão é igual a nada, nem a ele mesmo.
Melhor que testar depois é evitar a conta impossível antes: if (x >= 0) { … sqrt(x) … }. É o que a missão final faz.
Formas diferentes de fazer a mesma conta
| Conta | Formas | Qual usar |
|---|---|---|
| Quadrado | x * x ou pow(x, 2) | x * x: mais simples, e funciona com int |
| Raiz quadrada | sqrt(x) ou pow(x, 0.5) | sqrt: mais clara e mais precisa |
| Raiz cúbica | cbrt(x) ou pow(x, 1.0 / 3) | cbrt ("cube root"): funciona também com negativos (pow(-27, 1.0/3) dá nan) |
| Hipotenusa | sqrt(a*a + b*b) ou hypot(a, b) | hypot, que não estoura com números enormes |
Maior de dois double | a > b ? a : b (ternário) ou fmax(a, b) | fmax/fmin (do math.h) deixam a intenção clara; para int, use o ternário |
| Mostrar com 2 casas | %.2f ou round(x * 100) / 100 | %.2f, se é só para a tela |
Quando dá errado
referência não definida para "sqrt" (undefined reference to `sqrt')
O que significa: o ligador não achou o código da função. Faltou o -lm, ou ele está antes do arquivo .c no comando. O mesmo vale para pow, round, floor e as outras.
Como consertar: gcc -std=c23 -Wall -Wextra arquivo.c -o programa -lm, com o -lm no fim. No Makefile, a biblioteca vai em LDLIBS = -lm; no CMake, em target_link_libraries(programa m).
error: implicit declaration of function ‘sqrt’
$ gcc -std=c23 -Wall -Wextra semmath.c -o semmath
semmath.c: In function ‘main’:
semmath.c:5:28: error: implicit declaration of function ‘sqrt’ [-Wimplicit-function-declaration]
5 | printf("Lado: %.1f\n", sqrt(area));
| ^~~~
semmath.c:2:1: note: include ‘<math.h>’ or provide a declaration of ‘sqrt’
1 | #include <stdio.h>
+++ |+#include <math.h>
2 |
semmath.c:5:28: warning: incompatible implicit declaration of built-in function ‘sqrt’ [-Wbuiltin-declaration-mismatch]
5 | printf("Lado: %.1f\n", sqrt(area));
| ^~~~
semmath.c:5:28: note: include ‘<math.h>’ or provide a declaration of ‘sqrt’
O que significa: faltou o #include <math.h>. O gcc até mostra onde pôr a linha (o +++ |+). No editor: call to undeclared library function 'sqrt' e include the header <math.h>.
Como consertar: #include <math.h> no topo. Para abs, o include é <stdlib.h>.
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’
O que significa: as funções de math.h devolvem double, e o %d é para int. O programa mostra lixo.
Como consertar: use %f (ou %.0f, %.2f), ou converta: (int) pow(2, 10).
warning: using integer absolute value function ‘abs’ when argument is of floating-point type
O que significa: abs é para int; com double, a parte depois da vírgula se perde.
Como consertar: fabs(x), com #include <math.h>.
error: invalid operands to binary % (have ‘double’ and ‘double’)
O que significa: o % só aceita inteiros.
Como consertar: fmod(a, b).
error: ‘M_PI’ undeclared
O que significa: o M_PI não é do C padrão, e com -std=c23 ele não existe.
Como consertar: constexpr double PI = 3.14159265358979323846; (ou #define, em C antigo).
O que significa: provavelmente o ângulo está em graus (as funções esperam radianos), ou uma divisão entre dois int perdeu a vírgula antes de chegar à função (ceil(40 / 12) é ceil(3)).
Como consertar: converta graus com * PI / 180; garanta um double na divisão (40.0 / 12 ou (double) ovos / por_caixa).
Referência rápida
Todas recebem e devolvem double e estão no <math.h>, menos as marcadas. Existem versões para float e long double com f e l no fim (sqrtf, sqrtl).
| Função | O que calcula | Exemplo |
|---|---|---|
sqrt(x) | Raiz quadrada | sqrt(49.0) → 7 |
cbrt(x) | Raiz cúbica | cbrt(27.0) → 3 |
pow(b, e) | b elevado a e | pow(2, 10) → 1024 |
fabs(x) | Valor absoluto de double | fabs(-2.5) → 2.5 |
abs(n), labs, llabs | Valor absoluto de inteiro (<stdlib.h>) | abs(-35) → 35 |
round(x) | Inteiro mais próximo (,5 para longe do zero) | round(2.5) → 3 |
lround(x) | Como round, mas devolve long | lround(2.5) → 3 |
floor(x) | Para baixo | floor(-2.4) → −3 |
ceil(x) | Para cima | ceil(3.1) → 4 |
trunc(x) | Corta a parte depois da vírgula | trunc(-2.6) → −2 |
fmod(a, b) | Resto da divisão com vírgula | fmod(7.5, 2.0) → 1.5 |
hypot(a, b) | √(a² + b²) | hypot(3, 4) → 5 |
fmin(a, b), fmax(a, b) | Menor e maior de dois | fmax(-5.0, 0.0) → 0 |
sin, cos, tan | Seno, cosseno, tangente (em radianos) | sin(PI / 6) → 0.5 |
asin, acos, atan, atan2(y, x) | Os inversos (devolvem radianos) | acos(-1.0) → π |
exp(x), log(x) | ex e logaritmo natural | log(exp(2.0)) → 2 |
log10(x), log2(x) | Logaritmo na base 10 e na base 2 | log10(1000.0) → 3 |
isnan(x), isinf(x) | É "não número"? É infinito? | isnan(sqrt(-1.0)) → verdadeiro |
-lm | Opção do gcc que liga a biblioteca de matemática (no fim do comando) | gcc a.c -o a -lm |
Exercícios
1. A raiz
Complete para guardar em r a raiz quadrada de x:
2. A opção do gcc
Complete o comando para o ligador encontrar a sqrt:
3. Sempre para cima
Que função dá o número de ônibus necessários para levar 130 alunos em ônibus de 40 lugares (130.0 / 40 = 3,25 → 4)?
4. O que floor(-2.5) devolve?
5. Por que gcc -lm raiz.c -o raiz dá referência não definida para "sqrt"?
6. Qual linha mostra o resultado de pow(2, 10) corretamente?
Missão final: as raízes da equação
Missão: a lição de casa da Ana é achar as raízes de equações do 2º grau (ax² + bx + c = 0) com a fórmula de Bhaskara. Complete a função raizes, que já calcula o delta (b² − 4ac):
- se
delta < 0, mostresem raízes reais(não chame asqrtcom número negativo); - senão, calcule
x1 = (-b + √delta) / (2a)ex2 = (-b - √delta) / (2a)e mostrex1 = …, x2 = …, com duas casas.
A saída tem de ser exatamente esta, sem avisos:
x² - 5x + 6: x1 = 3.00, x2 = 2.00 2x² + 4x - 6: x1 = 1.00, x2 = -3.00 x² + 2x + 5: sem raízes reais
#include <stdio.h>
#include <math.h>
void raizes(double a, double b, double c) {
double delta = b * b - 4 * a * c;
// se delta < 0: mostre "sem raízes reais"
// senão: calcule x1 e x2 e mostre "x1 = ..., x2 = ..."
}
int main(void) {
printf("x² - 5x + 6: ");
raizes(1, -5, 6);
printf("2x² + 4x - 6: ");
raizes(2, 4, -6);
printf("x² + 2x + 5: ");
raizes(1, 2, 5);
return 0;
}
#include <stdio.h>
#include <math.h>
void raizes(double a, double b, double c) {
double delta = b * b - 4 * a * c;
if (delta < 0) {
printf("sem raízes reais\n");
return;
}
double x1 = (-b + sqrt(delta)) / (2 * a);
double x2 = (-b - sqrt(delta)) / (2 * a);
printf("x1 = %.2f, x2 = %.2f\n", x1, x2);
}
int main(void) {
printf("x² - 5x + 6: ");
raizes(1, -5, 6);
printf("2x² + 4x - 6: ");
raizes(2, 4, -6);
printf("x² + 2x + 5: ");
raizes(1, 2, 5);
return 0;
}
No terminal do Linux, este programa precisa do -lm, porque a sqrt recebe uma variável (delta). Repare também no (2 * a) entre parênteses: sem eles, / 2 * a dividiria por 2 e depois multiplicaria por a (Precedência).
Resumo
#include <math.h>traz as funções de matemática. Elas recebem e devolvemdouble: mostre com%f.- No Linux, o gcc precisa de
-lmno fim do comando; sem ele,referência não definida para "sqrt". Com números fixos o gcc às vezes calcula sozinho e o erro some, mas não conte com isso. O editor não precisa de-lm. sqrt(raiz),pow(potência; o^não é potência),fabs(absoluto dedouble;absé paraint, nostdlib.h).- Arredondar:
round(mais próximo),floor(para baixo),ceil(para cima),trunc(corta). Cuidado com a divisão inteira antes da função. fmodé o resto com vírgula;hypot, a distância; seno e cosseno usam radianos.- O
M_PInão é padrão: useconstexpr double PI = 3.14159265358979323846;. - Conta impossível dá
nanouinf; teste comisnan/isinfou, melhor, evite a conta antes. - Próxima aula: Números Aleatórios (rand).