Um número inteiro positivo n é primo se for divisível apenas por 1 e por n:
2, 3, 5, 7, 11, 13 …
Vamos especificar um algoritmo para testar se um número é primo.
Dado: n inteiro.
Se n≤1 então não é primo e terminamos imediatamente.
Se n>1 tentamos para d=2,3,…,n−1:
Se chegamos ao final sem encontrar um divisor: concluimos que n é primo.
#define FALSE 0
#define TRUE 1
/* Testar se um número inteiro é primo */
int primo(int n) {
int d;
if(n <= 1) return FALSE;
for (d = 2; d < n; d++) {
if (n%d == 0) // d divide n?
return FALSE;
}
return TRUE;
}
/* Testar se um número é primo;
versão mais eficiente */
int primo(int n)
{
int d;
if(n <= 1) return FALSE;
for (d = 2; d*d <= n; d++) {
if (n%d == 0) // d divide n
return FALSE;
}
return TRUE;
}
O máximo divisor comum (mdc) de dois inteiros a,b é o maior número inteiro que divide a e b.
Exemplo:
252=21×12105=21×5
Dados: a,b dois números inteiros positivos.
Calcular o mdc de 252 e 105.
iter | a | b |
---|---|---|
0 | 252 | 105 |
1 | 147 | 105 |
2 | 42 | 105 |
3 | 42 | 63 |
4 | 42 | 21 |
5 | 21 | 21 |
R: 21
/* Calcular o mdc de dois inteiros positivos
pelo Algoritmo de Euclides (1ª versão)
*/
int mdc(int a, int b)
{
while (a != b) {
if(a > b)
= a - b;
a else
= b - a;
b }
return a; // a, b são iguais
}
OK:
Questões:
Propriedade da divisão inteira:
Se d divide a e b, então d divide a−b e d divide b−a.
Em cada iteração:
se a>b:(a,b)⟶(a−b,b)se a<b:(a,b)⟶(a,b−a)
(Versão usando resto da divisão.)
Dados: a,b dois inteiros não-negativos.
Calcular o mdc de 252 e 105.
iter | a | b | resto a ÷ b |
---|---|---|---|
0 | 252 | 105 | 42 |
1 | 105 | 42 | 21 |
2 | 42 | 21 | 0 |
3 | 21 | 0 |
R: 21
/* Calcular o mdc de dois inteiros usando
o algoritmo de Euclides (2ª versão)
*/
int mdc(int a, int b)
{
int r;
while(b != 0) {
= a%b;
r = b;
a = r;
b }
return a;
}
fact(0)=1fact(n)=n×fact(n−1),se n>0
A definição anterior define um algoritmo: permite calcular o factorial de qualquer inteiro não negativo.
Exemplo:
fact(4)=4×fact(3)=4×(3×fact(2))=4×(3×(2×fact(1)))=4×(3×(2×(1×fact(0)))=4×(3×(2×(1×1)))=24
Podemos implementar este processo defindo a função recursiva em C:
int fact(int n)
{
if (n == 0)
return 1; // caso base
else
return n * fact(n-1); // caso recursivo
}
Há dois casos na definição anterior:
o factorial de zero é 1 (sem mais chamadas recursivas)
calculamos o factorial do natural anterior e multiplicamos o resultado por n
Para que uma definição recursiva termine é suficiente que:
Exemplo: na função de fact
n == 0
n-1
n
)Logo: fact
termina para qualquer n
maior ou
igual a 0.
int fact(int n) {
int r = 1; // resultado
for(int i = 1; i<=n; i++)
= r*i;
r return r;
}
int
e float
int
têm
sinal: podem ser negativos, positivos ou zerounsigned int
para inteiros sem sinal: apenas positivos ou zeroint i; // com sinal
unsigned int j; // sem sinal
unsigned
:unsigned j; // unsigned int
int
e unsigned int
são ambos representados por palavras de comprimento fixo
mínimo0(0000000000000000)21(0000000000000001)22(0000000000000010)2⋮⋮máximo216−1(1111111111111111)2
mínimo−215(1000000000000000)2⋮⋮−1(1111111111111111)20(0000000000000000)2+1(0000000000000001)2⋮⋮máximo+215−1(0111111111111111)2
int
é tipicamente representado usando 32-bits (pode ser menor em
CPUs de 8 e 16-bits)long
e short
para
especificar tamanhos maiores ou menoresunsigned
temos 6
tipos diferentes de inteiros:short int unsigned short int
int unsigned int
long int unsigned long int
int
short
≤ int
≤ long
<limits.h>
define os limites de cada tipo#include <stdio.h>
#include <limits.h>
int main(void) {
("SHRT_MIN = %d\n", SHRT_MIN);
printf("SHRT_MAX = %d\n", SHRT_MAX);
printf
("INT_MIN = %d\n", INT_MIN);
printf("INT_MAX = %d\n", INT_MAX);
printf
("LONG_MIN = %ld\n", LONG_MIN);
printf("LONG_MAX = %ld\n", LONG_MAX);
printf// %ld para formatar long int
}
Execução no meu portátil (GNU/Linux X86-64):
$ ./tamanhos
SHRT_MIN = -32768
SHRT_MAX = 32767
INT_MIN = -2147483648
INT_MAX = 2147483647
LONG_MIN = -9223372036854775808
LONG_MAX = 9223372036854775807
int
long int
long
terminando com
L
ou l
e unsigned
com
U
ou u
:17 // int
-1000L // long int
2500UL // unsigned long int
long int i = 17; // 17 -> 17L
Para ler ou escrever inteiros short
, long
ou unsigned
devemos
usar formatos específicos em scanf
e
printf
.
Casos mais comuns:
"%u"
inteiro decimal unsigned
"%ld"
inteiro decimal long
"%lu"
inteiro decimal unsigned long
int
para as
dimensõesl = w = h = 1500
resulta em overflow (inteiros de 32-bits)unsigned
unsigned long
#include <stdio.h>
int main(void) {
unsigned l, w, h, v;
("L=?"); scanf("%u", &l);
printf("W=?"); scanf("%u", &w);
printf("H=?"); scanf("%u", &h);
printf= l*w*h; // cálculo do volume
v
("LxWxH: %u*%u*%u (cm)\n", l,w,h);
printf("Volume: %u (cm^3)\n", v);
printf}
Esta versão calcula o volume correto para
= w = h = 1500 l
mas obtemos de novo overflow para
= w = h = 2000 l
#include <stdio.h>
int main(void) {
unsigned long l, w, h, v;
("L=?"); scanf("%lu", &l);
printf("W=?"); scanf("%lu", &w);
printf("H=?"); scanf("%lu", &h);
printf= l*w*h; // cálculo do volume
v
("LxWxH: %lu*%lu*%lu (cm)\n", l,w,h);
printf("Volume: %lu (cm^3)\n", v);
printf}
l = w = h = 2000
l = w = h
para os quais não ocorre overflow (assumindo
unsigned long
com 64-bits)float
para
precisão simples;double
para precisão dupla.tipo | menor positivo | maior valor | precisão |
---|---|---|---|
float | ≈1.17×10−38 | ≈3.40×1038 | 6 algarismos |
double | ≈2.22×10−308 | ≈1.79×10308 | 15 algarismos |
double
é
usado para a maior parte das aplicaçõesfloat
é
usando apenas se a precisão for pouco importante ou para poupar
memória57.0 57. 57E0 5.7e1
E
(ou e
)5.7e1 |
5.7×101 |
5.7E-3 |
5.7×10−3 |
"%lf"
para ler valores double
float
ou double
devemos usar
apenas "%f"
"%g"
para formatar usando
notação científica#include <stdio.h>
int main(void) {
double l, w, h, v;
("L=?"); scanf("%lf", &l);
printf("W=?"); scanf("%lf", &w);
printf("H=?"); scanf("%lf", &h);
printf= l*w*h; // cálculo do volume
v
("LxWxH: %.3f*%.3f*%.3f (cm)\n",
printf, w, h);
l("Volume: %.3g (cm^3)\n", v);
printf}
Conversão explicita de tipos (“cast”):
(int) expr |
converter para inteiro |
(float) expr |
converter para vírgula flutuante |
(tipo) expr |
forma geral |
int k = 2, n = 3;
("%f\n", (float)k/(float)n); // 0.66666
printf("%f\n", (float)k/n); // 0.66666
printf("%f\n", (float)(k/n)); // 0.00000 printf
Também podemos converter entre tamanhos:
int i = 1500;
long j;
= (long)i; j
Devemos efetuar conversões antes de operações que possam causar overflow:
int i = 1500;
long j;
= (long)(i*i*i); // "overflow"(?)
j = (long)i*i*i; // OK j