Risolto Algoritmo che dice il giorno datato

enk17

Utente Bronze
23 Ottobre 2021
69
17
8
37
Salve sto avendo un problema nel capire come funzioni questo codice ovvero questo codice (modificato un pò da me) inserito un giorno e un mese del 2022 dice che giorno è.

C++:
#include <iostream>
using namespace std;
int main()
{
    // useremo questa formula x = anno + (anno - 1) : 4 - (anno - 1) : 100 + (anno - 1) : 400 + tempo_trascorso, formuala di Algoritmo Doomsday

int giorno,mese,anno=2022,x=0,tempo_trascorso;
int mesi[13] ={1,31,59,90,120,151,181,212,243,273,304,334,365};
cout << "Inserire il giorno: ";
cin >> giorno;
cout << "Mese: ";
cin >> mese;

if(anno==2022)
{
x = anno + (anno-1)/4 - (anno-1)/100 + (anno - 1)/400;
tempo_trascorso=giorno+mesi[mese-1];

    if(mese > 2 && anno % 4 == 0 && (mese % 100 != 0 || anno % 400 == 0))
    {
    tempo_trascorso+=1;
    }
    
}else
{
x = anno + (anno-1)/4;
tempo_trascorso=giorno+mesi[mese-1];
tempo_trascorso-=2;


    if(mese > 2 && anno % 4 == 0 && (anno % 100 != 0 || anno % 400 == 0))
    {
    tempo_trascorso+=1;
    }
}

x+=tempo_trascorso;
x%=7;
cout <<"Il "<< giorno << "-" << mese << "-" << anno;
switch(x){
case 0:
cout << " é Sabato\n";
break;
case 1:
cout << " é Domenica\n";
break;
case 2:
cout << " é Lunedi\n";
break;
case 3:
cout << " é Martedi\n";
break;
case 4:
cout << " é Mercoledi\n";
break;
case 5:
cout << " é Giovedi\n";
break;
case 6:
cout << " é Venerdi\n";
break;
}

return 0;
}

Non riesco ben a capire i calcoli che fa (so solo che usa la formula dell'Algoritmo Doomsday) e di questa variabile.
int mesi[13] ={1,31,59,90,120,151,181,212,243,273,304,334,365};
 
Ti propongo un algoritmo più semplice e anche più corretto (nel tuo vedo un mese%100 che non ha molto senso).
C++:
#include <iostream>
using namespace std;

constexpr int yearday[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
constexpr const char *dayname[7] = {"Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica"};

int main() {
  int day, month, year;
  cout << "Inserire il giorno: ";
  cin >> day;
  cout << "Inserire il mese: ";
  cin >> month;
  cout << "Inserire l'anno: ";
  cin >> year;

  // Gli anni bisestili sono:
  // 1) tutti gli anni divisibili per 400; oppure
  // 2) gli anni non divisibili per 100 e divisibili per 4.
  bool leap = (year % 100 && !(year % 4)) || !(year % 400);

  // Conto il numero di giorni trascorsi dal "giorno zero". Vado a rappresentare
  // la data odierna come unico numero. Nota: sommare gli anni bisestili
  // equivale a sommare un giorno per ogni anno bisestile.
  int n =
      (year * 365)                // giorni trascorsi dal giorno zero all'inizio dell'anno
      + day + yearday[month - 1]  // giorni passati dall'inizio dell'anno ad oggi
      + (year / 400)              // anni bisestili trascorsi per la regola 1
      + (year / 4) - (year / 100) // anni bisestili trascorsi per la regola 2
      - (leap && month <= 2);     // quest anno è bisestile, ma non è passato il 29 febbraio

  // Le settimane si ripetono ciclicamente, quindi basterebbe stampare
  // dayname[n % 7]; tuttavia, vediamo che oggi (17-3-2022) è Sabato, ma
  // in realtà è Giovedì. Perché? Semplicemente, l'anno zero non era un Lunedì.
  // Sistemo la data di oggi con un +5 e tutte le altre seguono la correzione.
  cout << dayname[(n + 5) % 7] << endl;

  return 0;
}

I commenti dovrebbero essere abbastanza esaustivi, ma se hai qualche dubbio chiedi. L'unica cosa rimasta da spiegare sono i valori di yearday. Se volessimo fare un array con i giorni presenti in ogni mese scriveremmo:
C++:
constexpr int monthday[12] = {31, 28, 31, 30, 31, 30, 31, 30, 31, 31, 30, 31};
ma noi vogliamo un array che ci conta il numero di giorni trascorsi prima del mese attuale: prima di gennaio non ci sono giorni (0), prima di febbraio ci sono tutti i giorni di gennaio (31), prima di marzo ci sono tutti i giorni di gennaio e febbraio (31+28=59), prima di aprile ci sono tutti i giorni di gennaio, febbraio e marzo (31+28+31=90), etc... Se noti il tuo mesi[13] è molto simile al mio monthday[12]. Lo puoi calcolare così:
C++:
#include <iostream>
using namespace std;

constexpr int monthday[12] = {31, 28, 31, 30, 31, 30, 31, 30, 31, 31, 30, 31};

int main() {
  int sum = 0;

  cout << "constexpr int yearday[12] = {";
  for (int i = 0; i < 12; i++) {
    if (i != 0) cout << ", ";
    cout << sum;
    sum += monthday[i];
  }
  cout << "};\n";

  return 0;
}

so solo che usa la formula dell'Algoritmo Doomsday
L'algoritmo di Doomsday da quanto ho capito è un algoritmo mnemonico. Se hai un computer puoi permetterti di fare calcoli che a mente non sarebbero altrettanto immediati e usare l'approccio naive matematico.
 
Ti propongo un algoritmo più semplice e anche più corretto (nel tuo vedo un mese%100 che non ha molto senso).
C++:
#include <iostream>
using namespace std;

constexpr int yearday[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
constexpr const char *dayname[7] = {"Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica"};

int main() {
  int day, month, year;
  cout << "Inserire il giorno: ";
  cin >> day;
  cout << "Inserire il mese: ";
  cin >> month;
  cout << "Inserire l'anno: ";
  cin >> year;

  // Gli anni bisestili sono:
  // 1) tutti gli anni divisibili per 400; oppure
  // 2) gli anni non divisibili per 100 e divisibili per 4.
  bool leap = (year % 100 && !(year % 4)) || !(year % 400);

  // Conto il numero di giorni trascorsi dal "giorno zero". Vado a rappresentare
  // la data odierna come unico numero. Nota: sommare gli anni bisestili
  // equivale a sommare un giorno per ogni anno bisestile.
  int n =
      (year * 365)                // giorni trascorsi dal giorno zero all'inizio dell'anno
      + day + yearday[month - 1]  // giorni passati dall'inizio dell'anno ad oggi
      + (year / 400)              // anni bisestili trascorsi per la regola 1
      + (year / 4) - (year / 100) // anni bisestili trascorsi per la regola 2
      - (leap && month <= 2);     // quest anno è bisestile, ma non è passato il 29 febbraio

  // Le settimane si ripetono ciclicamente, quindi basterebbe stampare
  // dayname[n % 7]; tuttavia, vediamo che oggi (17-3-2022) è Sabato, ma
  // in realtà è Giovedì. Perché? Semplicemente, l'anno zero non era un Lunedì.
  // Sistemo la data di oggi con un +5 e tutte le altre seguono la correzione.
  cout << dayname[(n + 5) % 7] << endl;

  return 0;
}

I commenti dovrebbero essere abbastanza esaustivi, ma se hai qualche dubbio chiedi. L'unica cosa rimasta da spiegare sono i valori di yearday. Se volessimo fare un array con i giorni presenti in ogni mese scriveremmo:
C++:
constexpr int monthday[12] = {31, 28, 31, 30, 31, 30, 31, 30, 31, 31, 30, 31};
ma noi vogliamo un array che ci conta il numero di giorni trascorsi prima del mese attuale: prima di gennaio non ci sono giorni (0), prima di febbraio ci sono tutti i giorni di gennaio (31), prima di marzo ci sono tutti i giorni di gennaio e febbraio (31+28=59), prima di aprile ci sono tutti i giorni di gennaio, febbraio e marzo (31+28+31=90), etc... Se noti il tuo mesi[13] è molto simile al mio monthday[12]. Lo puoi calcolare così:
C++:
#include <iostream>
using namespace std;

constexpr int monthday[12] = {31, 28, 31, 30, 31, 30, 31, 30, 31, 31, 30, 31};

int main() {
  int sum = 0;

  cout << "constexpr int yearday[12] = {";
  for (int i = 0; i < 12; i++) {
    if (i != 0) cout << ", ";
    cout << sum;
    sum += monthday[i];
  }
  cout << "};\n";

  return 0;
}


L'algoritmo di Doomsday da quanto ho capito è un algoritmo mnemonico. Se hai un computer puoi permetterti di fare calcoli che a mente non sarebbero altrettanto immediati e usare l'approccio naive matematico.
Grazie per la spiegazione ora ho capito i calcoli che fa però mi è sorto un altro problema, il codice in questione è una funzione che quando provo a richiamarla non funziona.
C++:
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

int calendario(int giorno, int mese);

using namespace std;

int main()

{

   

    //string nomecognome[19] = { };
    int scelta,richiamo;
   
    richiamo=calendario(giorno,mese);

       cout << "     Programma per programmare le interrogazioni e turni.      \n\t";

 

    cout << "\n\tOpzioni: \n\t1-Genera un turno\n\t2-Esci\n\tScegli Opzioni: ";

    cin >> scelta;


    if(scelta==1)
    {
        for(int j=0;j<19;j++)
        {
            cout << "\n\t" << /*nomecognome[j]*/ << " viene interrogato il Giorno: " <<richiamo ;
        }
    }

   
   
    if(scelta==2)
    {
    cout << "Arrivederci!!";
    }
    return 0;
}


int calendario(int giorno,int mese)
{
srand(time(NULL));

bool estrazione_errata=true;
int s,data;
int yearday[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
char *dayname[7] = {"Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica"};
        for(int j=0;j<=18;j++)
        {
 
            while(estrazione_errata==true)
            {
                mese = rand()%12+1;
    //escludo i mesi estivi
                if(mese!=7 && mese!=8 && mese!=6)
                {
                    estrazione_errata=false;
                }
                if(mese==2){
                    data = rand()%28+1;
                }
                else if(mese==11 ||mese==6 ||mese==4||mese==9)
                {
                    data = rand()%30+1;
                }
                else{
                    data = rand()%31+1;

                   
                }
    //dopo aver esclusi i mesi estivi, escludiamo sabati, domeniche e mercoledì, ovvero i giorni in cui non vediamo il prof
                if(estrazione_errata==false)
                {
                    if(mese==1){
                     
                    }
                    else if(mese==2){
                     
                    }
                }

  bool leap = (2022 % 100 && !(2022 % 4)) || !(2022 % 400);

  int n =(2022 * 365)+ giorno + yearday[mese - 1]  + (2022 / 400)+ (2022 / 4) - (2022 / 100)- (leap && mese <= 2);    


  cout << dayname[(n + 5) % 7] << endl;

  return s;
}
}
}
 
Spiega (dettagliatamente) cosa dovrebbe fare il programma, poi ti faccio vedere come risolverlo.
Il programma dovrebbe generare in modo casuale le date delle interrogazioni di 19 studenti,la data che verrà generata (che deve escludere tutti i Mercoledì,sabato, domenica e i mesi estivi) e essere riconosciuta dall'algoritmo e dire che giorno corrisponde la data (facendo riferimento sempre solo al 2022) con stampa finale del nome dell'alunno con la data.
 
Sono rimasto sul semplice, poi sistematelo tu.
C++:
#include <iostream>
#include <random>

using namespace std;

int weekdaynum(int day, int month, int year) {
  constexpr int yearday[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  bool leap = (year % 100 && !(year % 4)) || !(year % 400);

  int n = (year * 365)
          + day + yearday[month - 1]
          + (year / 400)
          + (year / 4) - (year / 100)
          - (leap && month <= 2);

  return (n + 5) % 7;
}

template <class URNG> int rand_month(URNG &rng) {
  uniform_int_distribution<int> dist(1, 9);
  int val = dist(rng);
  if (val >= 6) val += 3; // skip summer
  return val;
}

template <class URNG> int rand_day(URNG &rng, int month) {
  constexpr int days[12] = {31, 28, 31, 30, 31, 30, 31, 30, 31, 31, 30, 31};
  uniform_int_distribution<int> dist(1, days[month - 1]);
  return dist(rng);
}

int main() {
  constexpr const char *dayname[7] = {"Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica"};
  constexpr const char *student[19] = {"A", "B", "C", "D", "E", "F", "G", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S"};

  random_device rd;
  mt19937 rng(rd());

  for (int i = 0; i < 19;) {
    int month = rand_month(rng);
    int day = rand_day(rng, month);
    int wday = weekdaynum(day, month, 2022);
    // skip mercoledì, sabato and domenica
    if (!(wday == 2 || wday == 5 || wday == 6))
      cout << student[i++] << " => " << day << "/" << month << "/2022 (" << dayname[wday] << ")\n";
  }

  return 0;
}
 
  • Mi piace
Reazioni: enk17
Sono rimasto sul semplice, poi sistematelo tu.
C++:
#include <iostream>
#include <random>

using namespace std;

int weekdaynum(int day, int month, int year) {
  constexpr int yearday[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  bool leap = (year % 100 && !(year % 4)) || !(year % 400);

  int n = (year * 365)
          + day + yearday[month - 1]
          + (year / 400)
          + (year / 4) - (year / 100)
          - (leap && month <= 2);

  return (n + 5) % 7;
}

template <class URNG> int rand_month(URNG &rng) {
  uniform_int_distribution<int> dist(1, 9);
  int val = dist(rng);
  if (val >= 6) val += 3; // skip summer
  return val;
}

template <class URNG> int rand_day(URNG &rng, int month) {
  constexpr int days[12] = {31, 28, 31, 30, 31, 30, 31, 30, 31, 31, 30, 31};
  uniform_int_distribution<int> dist(1, days[month - 1]);
  return dist(rng);
}

int main() {
  constexpr const char *dayname[7] = {"Lunedi", "Martedi", "Mercoledi", "Giovedi", "Venerdi", "Sabato", "Domenica"};
  constexpr const char *student[19] = {"A", "B", "C", "D", "E", "F", "G", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S"};

  random_device rd;
  mt19937 rng(rd());

  for (int i = 0; i < 19;) {
    int month = rand_month(rng);
    int day = rand_day(rng, month);
    int wday = weekdaynum(day, month, 2022);
    // skip mercoledì, sabato and domenica
    if (!(wday == 2 || wday == 5 || wday == 6))
      cout << student[i++] << " => " << day << "/" << month << "/2022 (" << dayname[wday] << ")\n";
  }

  return 0;
}
Grazie mille! Mi sei stato di ottimo aiuto!