2014-10-31 2 views
0

Это упражнение; Мне запрещено использовать встроенную функцию даты C++ или любую доступную библиотеку.Приращение дат в петле

У меня есть этот код:

#include <iostream> 
#include <vector> 

using namespace std; 


bool IsLeap(unsigned int year) 
{ 
    if (year % 4 != 0) return false; 
    else 
     if (year % 100 != 0) return true; 
     else 
      if (year % 400 != 0) return false; 
      else 
       return true; 
} 

class Date 
{ 
public: 
    unsigned short int Day; 
    unsigned short int Month; 
    unsigned short int Year; 
    unsigned short int DayOfWeek; 
}; 

int MonthLimit(int Month, int year) 
{ 
    switch (Month) 
    { 
    case 4: 
    case 6: 
    case 9: 
    case 11: 
    { 
     return 30; 
     break; 
    } 
    case 1: 
    case 3: 
    case 5: 
    case 7: 
    case 8: 
    case 12: 
    { 
     return 31; 
     break; 
    } 
    case 2: 
     if (IsLeap(year)) 
     { 
      return 29; 
      break; 
     } 
     else 
     { 
      return 28; 
      break; 
     } 

    } 
} 



const Date FirstDayEver = { 1, 1, 1900, 1 }; //January 1, 1900 was on a Monday. 

int main() 
{ 
    unsigned int years; 
    cin >> years; 

    vector<int> counters(7); //whenever a 13th falls on a day X, we increment the Xth counter. It's that simple 


    for (Date i = FirstDayEver; !((i.Day == 31) && (i.Month == 12) && (i.Year == 1900 + years - 1)); i.Day++) 
    { 
     i.DayOfWeek = (i.DayOfWeek + 1) % 7; 
     if (i.Month == MonthLimit(i.Month, i.Year)) 
     { 
      i.Month++; 
      i.Day = 1; 
      cout << "Proceeded to " << i.Day << "." << i.Month << "." << i.Year << "\n"; 
     } 
     if ((i.Day == 31) && (i.Month == 12)) 
     { 
      i.Year++; 
      i.Day = 1; 
      i.Month = 1; 
      cout << "Proceeded to " << i.Day << "." << i.Month << "." << i.Year << "\n"; 
     } 

     if (i.Day == 13) 
     { 
      counters[i.DayOfWeek]++; 
      cout << i.Day << "." << i.Month << "." << i.Year << " was a " << i.DayOfWeek << "\n"; 
     } 
    } 

    cout << counters[6] << " " << counters[7] << " " << counters[1] << " " << counters[2] << " " << counters[3] << " " << counters[4] << " " << counters[5] << "\n"; 

    exit(0); 
} 

отладочная информация (cout з) там, чтобы видеть, происходит ли что-нибудь в цикле. До сих пор единственное, что случается, - это много строк, в которых говорилось: «13.1.1900 было« разным числом ». Я думаю, что желаемая логика увеличения даты довольно ясна из кода, но я пытаюсь что-то привнести. Где моя ошибка?

+1

Как и в сторону, почему 'выхода (0);' вместо (неявное) 'вернуть 0;' в конце 'main'? – Deduplicator

+0

Это то, что меня просят сделать. Это как-то связано с тем, что мой код отправляется на Linux-машину, у которой, вероятно, возникают проблемы с простым «возвратом 0;». – Chiffa

+0

Нет, Linux, безусловно, прекрасен с более идиоматическим кодом. Взгляните на второй оператор 'if' в цикле. Это ... так неправильно (логика). Кроме того, подумайте о том, чтобы ввести код нормализации даты в функцию-член 'normalize()'. – Deduplicator

ответ

1

Прежде всего,

if (i.Month == MonthLimit(i.Month, i.Year)) 

сравнивает месяц с количеством дней в месяце.
С первого месяца 1, и этот месяц имеет 31 день, вы никогда не будете увеличивать месяц.
Поскольку вы никогда не увеличиваете месяц, вы никогда не будете увеличивать год.
(Вы, вероятно, заметили это проще, если бы вы назвали функцию «DAYSINMONTH», или что-то другое, что делает его более ясным, что она возвращает.)

Вы хотите

if (i.Day == MonthLimit(i.Month, i.Year)) 

Во-вторых, MonthLimit отсутствует дело за октябрь.

+0

Да, первая часть верна, и явная ошибка с моей стороны. Благодарю. – Chiffa

1

Вы слишком усложняете процедуру приращения.
Я на самом деле все еще пытаюсь выяснить, как все это подходит (кромки и т. Д.), Но кажется, что вы пытались делать каждый день/месяц/год независимо.

Вы можете сделать все ваши в приращение простой функции, как это:

void increment_Date(Date &d) 
{ 
    d.DayOfWeek = (d.DayOfWeek + 1) % 7; //increase weekday 
    if (++d.Day > MonthLimit(d.Month, d.Year)//increase day, if larger than month size... 
    { 
     d.Day = 1;       //reset day to 1 
     if (++d.Month > 12)     //increase month, if larger than year size 
     { 
      d.Month = 1;      //reset month to 1 
      d.Year++;       //increase year 
     } 
    } 
} 

Логика проще, потому что я подошел к ней в несколько иначе, чем вы, кажется, сделали.
В приведенной выше функции я увеличиваю наименьшую единицу сначала (день), проверяю переполнение, а затем при необходимости перемещаюсь до месяца (и так далее).

Это работает так же, как цифры циферблата пробега автомобиля только тикают, когда циферблат достигает 10 и возвращается к 0. Или, добавив от 1 до 9 и «переполненный» цифрой 10 цифр.

В противном случае ваш код хорош. Оператор Switch для MonthLimit был хорошим выбором. я бы добавить переключатель заявление в функции возвращает строку в день недели:

std::String printable_DOW(int DOW) 
{ 
    switch (DOW) 
    case 0: 
     return "Sunday"; 
    case 1: 
     return "Monday"; 
    case 2: 
     return "Tuesday"; 
    case 3: 
     return "Wednesday"; 
    case 4: 
     return "Thursday"; 
    case 5: 
     return "Friday"; 
    case 6: 
     return "Saturday"; 
} 

и print_date функции тоже:

void print_date(Date d) 
{ 
    std::cout<< printable_DOW(d.DayOfWeek) 
      << ", " << d.Day << "." << d.Month << "." d.Year; 
} 

, и это довольно легко поставить все это вместе и использовать также:

int main 
{ 

    Date my_date; 
    my_date.Day = 1; 
    my_date.Month = 1; 
    my_date.Year = 2000; 
    my_date.DayOfWeek = 0; //assuming 0 == Sunday, 1 = Monday... 
    for (int daycount = 0; daycount < 5114 /*days since 1/1/2000 to today*/; daycount++) 
    { 
     increment_date(my_date); 
     //debug: 
     print_date(my_date); 
    } 
    //print "today's" date: 
    print_date(my_date); 
} 

Как класс: Это в основном здесь, и (в основном) работы. Не стесняйтесь редактировать людей!

class date 
{ 
private: 
    unsigned short int day; 
    unsigned short int month; 
    unsigned short int year; 
    unsigned short int day_of_week; 
    int month_limit(); 
    bool is_leap_year(); 
public: 
    date(); 
    date(int in_day, int in_month, int in_year, int in_day_of_week); 
    date& date::operator=(date rhs) 
    date& operator++(); //pre-increment (++date) 
    date operator++(int); //post-increment (date++) 

    //these are "special" they don't work exactly as you might think and are slightly broken right now, 
    //but I'm putting them in regardless 
    //they also don't work on DOW right now. 
    date& operator+=(const date& rhs)    
    date& operator-=(const date& rhs) 
    inline date operator+(date lhs, const date& rhs) 
    inline date operator-(date lhs, const date& rhs) 
} 
//phwew 

date::date(int in_day, int in_month, int in_year, int in_day_of_week) 
{ 
    this->day = in_day; 
    this->month = in_month; 
    this->year = in_year; 
    this->day_of_week = in_doay_of_week; 
} 

date::month_limit() 
{ 
    switch (this->month) 
    { 
    case 4: 
    case 6: 
    case 9: 
    case 11: 
    { 
     return 30; 
     break; 
    } 
    case 1: 
    case 3: 
    case 5: 
    case 7: 
    case 8: 
    case 12: 
    { 
     return 31; 
     break; 
    } 
    case 2: 
     if (is_leap_year(this->year)) 
     { 
      return 29; 
      break; 
     } 
     else 
     { 
      return 28; 
      break; 
     } 

    } 
} 

bool is_leap_year() 
{ 
    if (this->year % 4 != 0) return false; 
    else 
     if (this->year % 100 != 0) return true; 
     else 
      if (this->year % 400 != 0) return false; 
      else 
       return true; 
} 

date& date::operator=(date rhs) 
{ 
    swap(rhs); 
    return *this; 
} 

date& date::operator++() 
{ 
    this->day_of_week = (this->day_of_week + 1) % 7; //increase weekday 
    this->day++; 
    if (++(this->day) > month_limit())   //increase day, if larger than month size... 
     { 
      this->day = 1;       //reset day to 1 
      if (++this->month > 12)     //increase month, if larger than year size 
      { 
       this->month = 1;      //reset month to 1 
       this->year++;       //increase year 
      } 
     } 
    return *this; 
} 

date date::operator++(int) 
{ 
    date tmp(*this); 
    operator++(); 
    return tmp; 
} 

//adds years on, then months, then days 
date& date::operator+=(const date& rhs) 
{ 
    this->year += rhs.year; 
    this->month += rhs.month; 
    this->day += rhs.day; 
    if (this->month > 12) //get to the right month 
    { 
     this->year = this->month/12; 
     this->month = this->month % 12; 
    } 
    if (this->day > month_limit()) 
    { 
     this->month = this->day/month_limit(); 
     this->day = this->day % month_limit(); 
     if (this->month > 12) //recalculate **yes, I know this is currently wrong if more than one month is added on in days** 
     { 
      this->year = this->month/12; 
      this->month = this->month % 12; 
     } 
    } 
    return *this; 
} 

inline date date::operator+(date lhs, const date& rhs) 
{ 
    lhs += rhs; 
    return lhs; 
} 

//subtracts years, then months, then days 
date& date::operator-=(const date& rhs) 
{ 
    if ((rhs.year < this->year) || ((rhs.year == this->year) && (rhs.month < this->month)) 
     || (((rhs.year == this->year) && (rhs.month == this->month)) && (rhs.day < this->day) 
    { 
     swap(rhs); 
    } 
    this->year -= rhs.year; 
    this->month -= rhs.month; 
    this->day -= rhs.day; 

    return *this; 
} 

inline date date::operator+(date lhs, const date& rhs) 
{ 
    lhs += rhs; 
    return lhs; 
} 
+0

Ничего себе. Я об этом не думал. – Chiffa

+0

Теперь сделайте его функцией-членом и приращением-оператором. – Deduplicator

+0

'MonthLimit' также принимает' int year'. Я попытался реализовать логику «инкремент наименьшей единицы первой», но она потерялась в 'if's. – Chiffa

Смежные вопросы