sábado, 14 de março de 2015

[P5] Sexta-Feira 13

     Ontem foi uma sexta-feira 13. Será que as sextas-feiras 13 são tão especiais assim? Será que existem mais sexta-feiras 13 do que qualquer outro dia? Este post vai tratar deste tema, mas primeiro é necessário falar de calendários e anos bissextos.

Anos bissextos

     O calendário gregoriano é utilizado por nós ocidentais desde 1582 instituído pelo Papa Gregório em substituição ao calendário juliano. Ele é mais preciso e corrige erros introduzidos pelo calendário juliano.
     No calendário gregoriano um ano compreende 365 dias, mas como um ano ao redor do sol possui 365,2422 dias (ou seja, 365 dias, 5 horas, 48 minutos e 46 segundos), estes resíduos devem ser levados em consideração. Portanto, a cada 4 anos um ano deve ser bissexto, corrigindo este problema (0,25 * 4 = 1), resolvendo o problema em parte (pois se fossem 6 horas de resíduos fecharia um dia completo a cada quatro anos, entretanto, o resíduo é de 5 horas, 48 minutos e 46 segundos). É escolhida a data 29/Fevereiro para a adição do dia bissexto no calendário.
     Deve-se então, considerar a existência do resíduo equivalente a 0,2422 por ano. Ou seja, a cada 4 anos, são 'perdidos' 83704 segundos, que são corrigidos no ano bissexto, com o acréscimo de um dia. MAS, um dia tem 86400 segundos, então sobram 2696 segundos a cada quatro anos que devem ser considerados. Isto equivale a 44,93 minutos a cada quatro anos. Logo, para corrigir este pequeno resíduo, a regra de cálculo de ano bissexto diz que se o ano é divisível por 100, para ser bissexto, ele também deve ser divisível por 400. Por exemplo, 1800 não é bissexto, pois apesar de ser divisível por 4 e por 100, não é divisível por 400.

Quantidades de dias para os meses do ano

     A tabela a seguir mostra a quantidade de dias por mês do ano:
  Mês # Dias
01  Janeiro 31
02  Fevereiro 28 ou 29
03  Março 31
04  Abril 30
05  Maio 31
06  Junho 30
07  Julho 31
08  Agosto 31
09  Setembro 30
10  Outubro 31
11  Novembro 30
12  Dezembro 31

     Ou seja, existem 7*31+4*30+28 dias no ano, totalizando 365 dias (+1 se bissexto).

Funções em C para o cálculo de anos bissextos

     A seguir, é apresentada uma função em C para determinar se um ano (passado por parâmetro) é ou não bissexto:
char bissexto(int ano) {
  if (ano % 400 == 0)
     return 1;
  else if (ano % 4 == 0 && ano % 100 != 0)
          return 1;
  return 0;
}
     Esta função poderia ser mais simples (dependendo do ponto de vista, é claro), com o uso de ternários, por exemplo:
char bissexto2(int ano) {
  return (ano % 400 && ano % 4 == 0 && ano % 100 != 0 ? 1 : 0);
}
     A seguir, um exemplo completo, escrito em C:
#include <stdio.h>

// prototipos de funcoes
char bissexto(int ano);
char bissexto2(int ano);

int main(int argc, char *argv[]) {
   int ano = 2015;
   char resultado = bissexto2(ano);

   if (resultado == 1)
       printf("O ano %d e bissexto!", ano);
   else
       printf("O ano %d nao e bissexto!", ano);

   return 0;
}

char bissexto(int ano) {
  if (ano % 400 == 0)
     return 1;
  else if (ano % 4 == 0 && ano % 100 != 0)
          return 1;
  return 0;
}

char bissexto2(int ano) {
  return (ano % 400 && ano % 4 == 0 && ano % 100 != 0 ? 1 : 0);
}

Problema da contagem das sextas-feiras 13

     O intervalo, em anos, a ser considerado será de 1/Janeiro/1900 até 31/Dezembro/2078, pois é o intervalo que o MS-Excel trabalha, apenas por comodidade e para que seja possível validar os resultados obtidos aqui.
     Para começar o projeto desta postagem, assume-se como fato que:

  O dia 1o de Janeiro de 1900 foi uma Segunda-feira.  

Formatos de datas e representação em C

     Serão utilizados dois formatos de datas neste projeto:
  1. DD-MM-AAAA, equivalendo a D=dia, M=mês, A=ano
  2. DD-MM-AAAA HH:MM:SS, equivalendo a D=dia, M=mês, A=ano, H=hora, M=minuto, S=segundo
     Em C, pode-se utilizar um vetor de caracteres para representar estes formatos, das seguintes maneiras:
...
char data1[11]; // para o formato DD-MM-AAAA (incluindo o '\0')
char data2[20]; // para o formato DD-MM-AAAA HH:MM:SS (incluindo o '\0')
...
// utilizando ponteiros para vetor de caracteres
char* data3 = (char*) malloc(sizeof(char) * 10 + 1);
char* data4 = (char*) malloc(sizeof(char) * 19 + 1);
...
free(data3);
free(data4);
...

Implementação

     Isso é tudo que é necessário para começar este projeto. Para este projeto, considere o máximo de 178 anos (ou 2136 meses) do intervalo compreendido entre 1/1/1900 e 31/12/2078 e realize as funções solicitadas.

Questões interessantes deste projeto
  1. Faça uma biblioteca de funções que operam sobre datas, parecida com as existentes no MS-Excel:
    1. Faça uma função que recebe um formato completo de datas (DD-MM-AAAA HH:MM:SS) e um inteiro representando o que deseja-se retornar (0-dia, 1-mês,2-ano,3-hora,4-minuto,5-segundo)
    2. Faça uma função que passa uma data por parâmetro (formato DD-MM-AAAA) e esta retorna o dia da semana (de 0-7, sendo 0 para Domingo, 1 para Segunda e assim por diante)
    3. Faça uma função que converte um valor com data e hora (formato DD-MM-AAAA HH:MM:SS) informando o total em segundos decorridos desde 1/1/1900 e também desde 1/1/1970 até a data informada (utilize um parâmetro para requisitar o ano de cálculo, se 1900 ou 1970 ou outro qualquer)
    4. Faça uma função que recebe um valor correspondente à um tempo decorrido em segundos e retorna uma data no formato DD-MM-AAAA HH:MM:SS
    5. Faça uma função que recebe duas datas e informa o total de tempo decorrido (no formato DD-MM-AAAA HH:MM:SS). Se a primeira data for menor que a segunda, a função retorna -1
    6. Faça uma função que recebe uma data (formato DD-MM-AAAA) e uma quantidade em dias e a função retorna uma nova data somando os dias passados por parâmetro (por exemplo, Data="10-05-2015", Qtd=10, Resposta="20-05-2015")
  2. Quantos Sábados, Domingos, Segundas, Terças, Quartas, Quintas e Sextas-Feiras com dia igual a 13 existem de 1/1/1900 até 31/12/2078?
    1. Conforme um intervalo de datas passado no formato DD-MM-AAAA, calcule o mesmo total do item anterior.
  3. Você nasceu em que dia da semana? Faça uma função que recebe uma data e retorna o dia da semana (0 para Domingo, 1 para Segunda, e assim por diante)
  4. A partir de uma data especificada por parâmetro (DD-MM-AAAA), quando será a próxima Sexta-Feira 13?
  5. Quantos anos bissextos existem entre dois anos informados por parâmetro (por exemplo, entre 1900 e 2000)?
  6. Construa opções de linha de comando para acessar todas as funções definidas neste projeto
  7. [DESAFIO] Existe um dia e um dia da semana que mais ocorre? Por exemplo, Quinta-feira 12 (esta data é um exemplo!) é a data mais recorrente em todo o calendário (de 1/1/1970 até 31/12/2078)

Nenhum comentário:

Postar um comentário