sábado, 20 de abril de 2013

Soma de ponto com vetor

Definição: seja P um ponto e u um vetor qualquer. Definimos

  • P + u = Q <=> u = PQ
  • P - u = P + (-u)
  • P + PQ = Q
Propriedades:
  • A + u = A + v => u = v
  • A + u = B + u => A = B
  • (A + u) + v = A + (u + v)
  • (A + u) - u = A
Exemplos:
1 - 2 - 3 - 4

Exercício resolvido: GAAV - soma de ponto com vetor 2

Dado o triângulo ABC onde M e N são os pontos médios dos lados AC e CB, respectivamente, mostre que MN // AB e ||MN|| = 1/2 ||AB||


Observação para ajudar no raciocínio: Se MN é o vetor AB multiplicado por 1/2, isso implica que eles são paralelos. Agora vamos lá provar isso:


Exercício resolvido: GAAV - soma de ponto com vetor 1

Determine o ponto X tal que (A + AB) + CX = C + CB


Multiplicação por escalar

Definição: sejam α um número real e v um vetor qualquer. Definimos αv

  • α = 0 ou v = 0 => αv = 0
  • α ≠ 0 e v ≠ 0 então αv é o vetor tal que:
    • ||αv|| = |α|*||v||
    • αv // v
    • αv tem mesmo sentido de v se α > 0
    • αv tem sentido oposto de v se α < 0
Propriedades: 
  • α (v + u) = αv + αu
  • (α + β) u = αu  + βu
  • 1 * u = u;
  • (αβ) u = α(βu) = β(αu)
Observações:
  • o versor de um vetor: dado u vetor qualquer diferente do nulo, o versor de u é v = (1/||u||) u = /||u|| (gera um vetor de norma 1)
  • regra de sinais: (-α)v = -(αv) = α(-v) e (-α)(-v) = αv
  • sejam u e v vetores quaisquer diferentes do nulo. Se u//v, então uαv para algum α  real. Ou seja, se forem paralelos, algum número real os torna iguais. Este número é α = ||u||/||v||
  • multiplicar um vetor por 0 resulta um vetor nulo.
  • sejam u e v vetores não paralelos e αu + βv = 0 => α = β = 0
    • o fato de dois vetores serem não paralelos implica que são ambos não nulos
  • sejam u e v vetores não paralelos e αu + βv = ɣu + δv => α ɣ e β = δ
Em resumo:


Soma de vetores

Em resumo, o resultado de uma soma de vetores é o vetor que lida a origem do primeiro à extremidade do segundo.
Definição: dados u e v, diferentes do vetor nulo, tome u = AB e v = CD. Definimos:

  • u + v = AC           (soma de vetores)
  • u - v = u + (-v)     (diferença de vetores)
Observação: Caso u e v sejam vetores paralelos, o resultado será um vetor com norma igual à soma das normas de u e v. Caso não sejam paralelos, pode-se usar a regra do paralelogramo:
Pergunta: ||u+v|| = ||u|| + ||v|| ? Em geral, NÃO. Para comprovar, lembre-se da condição de existência de triângulos (afinal, usando a regra do paralelogramo ou ligando a origem de v à extremidade de u e realizando a soma, formam-se triângulos): o valor de um lado deve ser menor do que a soma dos outros dois lados e maior do que o valor absoluto da diferença entre eles.

Propriedades: Sejam u, v e w vetores quaisquer. Valem:
  • (u + v) + w = u + (v + w)     propriedade associativa
  • u + v = v + u                      propriedade comutativa
  • u + 0 = 0 + u = u                 o vetor nulo somado a qualquer outro dá o outro
  • u + (-u) = 0 = -u + u            um vetor somado ao seu oposto resulta no vetor nulo

Vetores

Definições e observações:
1) Segmento orientado
segmento de reta para o qual se fiou uma orientação (direção, sentido e comprimento).

  • Notação: (A, B), em que A e B são os pontos de origem e extremidade
  • Indicação: flecha
  • Observações:
    • O segmento orientado (A, A) será dito segmento orientado nulo;
    • (A, B) é diferente de (B, A).


                               AB = segmento de reta                 
                            (AB) = segmento orientado           
                      |AB| = comprimento do segmento 

2) Vamos dizer que:
  • (A, B) e (C, D) têm o mesmo comprimento se |AB| = |CD|
  • (A, B) e (C, D) têm a mesma direção se AB e CD são paralelos (inclui os coincidentes)
  • (A, B) e (C, D) têm o mesmo sentido se:
    • paralelos e não coincidentes: una as origens e extremidades. Se as linhas que as unem se cruzarem, o sentido dos segmentos é oposto. Se não, o sentido é o mesmo.
    • coincidentes: trace um segmento paralelo a um deles e repita o processo anterior.
  • Se A ≠ B, então (A, B) e (B, A) têm o mesmo comprimento, direção e sentidos opostos.


3) (A, B) e (C, D) são equipolentes se:
  • (A, B) e (C, D) são ambos nulos OU
  • se forem de mesmo comprimento, direção e sentido.
  • Notação: (A, B) ~ (C, D)
  • Observações:
    • (A, B) ~ (C, D) => (C, D) ~ (A, B)
    • (A, B) ~ (C, D) e (C, D) ~ (E, F) => (A, B) ~ (E, F)
    • (A, B) ~ (C, D) => (A, C) ~ (B, D)
  • Pergunta: Quantos equipolentes podemos construir para (A, B)? Infinitos, porque todos são diferentes entre si no contexto de segmentos orientados.

4) O vetor AB é:
O conjunto de todos os segmentos orientados equipolentes a (A, B). Qualquer elemento do conjunto é dito representante deste vetor.
  • Outras notações: (gente, não sei fazer aquelas setinhas em cima da letra)
  • Indicação:
  • Observações:
    • (C, D) ~ (A, B) => vetor CD = vetor AB.
    • dado u um vetor qualquer. Para qualquer ponto P, existe um ponto B tal que u = vetor PB. E ainda, B é único, isto é: vetor PA = vetor PB => A = B. Em outras palavras, se a origem é fixa, a extremidade é única.
5) Vetor nulo é o vetor representado por um segmento orientado nulo. Notação: um 0 (zero) com a setinha em cima.

6) Vetor oposto: se u = AB, então o vetor oposto de u é -u = BA.
  • Observações:
    • -(-u) = u
    • dado u qualquer e Q um ponto qualquer, então existe um único A tal que u = AQ. Em outras palavras, se a extremidade é fixa, a origem é única.
7) Vetores paralelos: u e v, ambos diferentes do vetor nulo, têm a mesma direção se possuem representantes paralelos. O vetor nulo é paralelo a todos os outros vetores, por convenção.

8) Vetores de mesmo sentido: u e v, ambos diferentes do vetor nulo, têm o mesmo sentido se u e v são paralelos e possuem representantes no mesmo sentido.

9) Norma: seja u um vetor qualquer, ||u|| (lê-se norma de u) = comprimento de seus representantes. Se ||u|| = 1, então dizemos que u é unitário.
  • Observações:
    • se u for diferente do vetor nulo, sua norma será maior que 0
    • se u for igual ao vetor nulo, sua norma será igual a 0
    • ||u|| = ||-u||
    • u = v => ||u|| = ||v|| e u//v

domingo, 7 de abril de 2013

Pré processador


Seguinte. Tem coisas que o programa faz antes de abrir a telinha que a gente vê. Os comandos que são interpretados pelo pré processador são aqueles iniciados em #: includes, macros e condicionais.

Os includes:
#include <stdio.h> //<> já reconhece bibliotecas “defaults”
#include “minhalib.h” //se for personalizada é entre aspas

As macros:
#define MAX 100
#define nome_macro texto_equivalente
Se uma macro ficar muito grande pra caber numa linha só, é só colocar uma barra invertida ( \ ) que o programa continua lendo. Ele só para de ler aquela macro quando acha uma linha sem a \.

É possível ter funções feitas com macros, assim:
#define MILHAS_KM(m) m*(8.0/5.0)
#define MULTI(a,b) ((a)*(b))

você chama a função escrevendo MILHAS_KM(sua_var) ou MULTI(v1,v2) e ele faz aquelas continhas! E pode ter comandos mais complexos:
#define IMPRIME_MSG(msg) \
printf ("Mensagem: %s\n", msg);
uso: IMPRIME_MSG("erro na fase y");

OBSERVAÇÃO IMPORTANTE: entre o nome da sua macro e a definição dela não pode ter espaço! Se eu colocasse #define MULTI (a, b) ← espaço entre a palavra e o parêntesis – daria errado porque no lugar de MULTI ele escreveria (a, b). O espaço só pode vir depois do nome inteiro.

As condicionais:
#if SISTEMA_OPERACIONAL== 1
  #include "windows.h"
#elif SISTEMA_OPERACIONAL == 4
  #include "hpux.h"
#else
  #error Sistema operacional não definido ou inválido
#endif
Só vai incluir “windows.h” se o SO definido for 1. A estrutura tem que ser essa chata aí mesmo

O resto:
#ifdef EXEMPLO //se tiver a define EXEMPLO
#ifndef EXEMPLO //se NÃO tiver a define EXEMPLO
#undef EXEMPLO //apaga a define EXEMPLO

Operações bit a bit


Então. Lembra que 1byte = 8bits? Existe jeito de manipular 1bit só. Tem vários operadores pra bits que até lembram alguns que a gente usa:
  • & AND operador lógico E
  • | OR operador lógico OU
  • ^ OR exclusivo operador lógico OU exclusivo (XOR)
  • << left shift deslocamento à esquerda
  • >> right shift deslocamento à direita
  • ~ complemento de um,  negação (NOT)
É só pensar que ele mexe com os bits das variáveis. Completarei mais tarde.

Listas encadeadas


Lembra que eu falei que podia colocar um struct dentro do mesmo struct? Pois é, assim que funcionam as listas encadeadas. De certa forma elas são como um vetor, tem vários objetos do mesmo tipo, mas no caso das listas pode ter quantos quiser (não o tamanho do vetor) e é bem mais manipulável.
A lógica das listas encadeadas é uma struct conter um ponteiro para o mesmo tipo. Dessa forma, um objeto vai se ligando do outro, porque ele aponta quem é o próximo da lista. Assim:

struct Nodo {
int dado;
struct Nodo *proximo;
} *raiz; //declara um ponteiro da struct Nodo chamado raiz

raiz = (Nodo *) malloc (sizeof(Nodo)); //aloca o tamanho da raiz
raiz->dado = 7; //preenche o dado
raiz->proximo = NULL; //fala que não tem próximo (ou seja, é o fim da lista)

Nodo *pnodo; //declara outro ponteiro, dessa vez chamado pnodo
pnodo = (Nodo *) malloc(sizeof(Nodo)); //aloca pnodo
pnodo->dado = 11; //preenche o dado
pnodo->proximo = NULL; //declara que é esse o fim da lista
raiz->proximo = pnodo; //fala que raiz agora deixa de ser o fim e aponta pra pnodo

Dessa forma, vai tendo uma continuidade, que um vai apontando pro outro. Esse tipo de lista é bem mais prático que um vetor, porque não tem um tamanho fixo e não precisa ser um logo seguido do outro (em termos de alocação de memória). Agora vamos aos procedimentos básicos:
  • Como percorrer uma lista encadeada utilizando um ponteiro
Nodo *pnodo;
pnodo = raiz;
while (pnodo != NULL) {
  printf(%d, pnodo->dado);
  pnodo = pnodo->proximo;
}
  • Como imprimir uma lista encadeada usando um ponteiro
void print_list (struct Nodo *pi) {
  printf("Lista = ");
  while (pi) {
    printf (" %d ", pi->dado);
    pi = pi->proximo;
  }
}

Alocação dinâmica de memória


É tipo assim. Quando você declara um int ou um char, por exemplo, essas variáveis tem um número de bytes pré definido pra ocupar. A alocação dinâmica de memória aloca exatamente o que você precisa.
Acaba que você não tem um vetor muito grande nem muito pequeno, porque sua variável vai ocupar exatamente o que você mandar.
São 4 funções: considerando int *p;

malloc: p = (int*) malloc(N * sizeof(int)); //aloca memória (N inteiros)
calloc: p = calloc(MAX_TAM, sizeof(int)); //aloca memória de tamanho MAX_TAM
realloc: p = (int *) realloc(x, 8000*sizeof(int)); //realoca memória de antes pro tamanho de 8000 inteiros
free: free(p); //libera a memória

É importante lembrar que quando se usa a alocação dinâmica é da NOSSA responsabilidade desalocar. Senão nem quando fechar o programa aquela alocação vai embora.
Outra coisa a acrescentar é sobre a função sizeof: ela retorna o tamanho em bytes daquele tipo de (ou do tipo daquela) variável.

Arquivos


Arquivos. São. Um. Porre. Vou até ser menos legal com eles. Declaração:
FILE *arquivo; //declarei um ponteiro que vai ser a representação do meu arquivo no programa
arquivo = fopen(nome, modo); //nome vem entre aspas e é o nome do arquivo que eu vou querer abrir, modo também vem entre aspas e diz o que eu vou fazer.



Esses são os modos. Agora as principais funções:
Abrir: arquivo = fopen(arquivo.txt,wb+);
Fim do arquivo: feof(arquivo);
Ler: fread (variável que vai receber, tamanho a ser lido, quantas vezes vai ler, arquivo);
Escrever: fwrite (var que vai escrever, tamanho a ser escrito, quantas vezes vai escrever, arquivo);
Posição do cursor: ftell(arquivo);
Volta o cursor pro começo: rewind(arquivo);
Posicionar o cursor: fseek(arquivo, tamanho a pular, de onde começa) //SEEK_SET = início, SEEK_END = final, SEEK_CUR = de onde está agora
Fechar: fclose(arquivo);
Também tem outras funções, como as de manipular diretamente char ou String (putc(caracter, arquivo) e puts(string, arquivo) para escrever, por exemplo). Mas com as que eu coloquei já dá pra trabalhar, portanto não vou aprofundar no assunto por agora.
Vou colocar um códigozinho aqui pra demonstrar algumas funções:

FILE *arq, *cop; //declarei meus dois arquivos
if (arq = fopen("arquivo.txt", "wb+" && cop = fopen("copia.txt", "wb+")) { //verifiquei se foi possível abrir os dois
   fseek(arq, 0, SEEK_SET); //coloquei o cursor no início
   fseek(cop, 0, SEEK_SET);
   while(!feof(arq)) { //enquanto não acabar o fim do arquivo arq
      char c;
      fread(c, 1, 1, arq); //eu leio 1 char de arq
      fwrite(c, 1, 1, cop); //e escrevo esse char em cop
   }
   fclose(arq); //fecho os dois ao final da cópia
   fclose(cop); //sempre importante fechar
} //fim

Escrevi aqui e agora, não compilei esse trem. Mas se não funcionar, o código correto é algo bem parecido. Esse está bem rudimentar porque eu não tratei muitos dos possíveis erros, só o da abertura de arquivo (se a abertura falhar, a função retorna NULL). Porém dá pra pegar mais ou menos o uso;