問題文は、各月の13日が特定の曜日になる頻度を[1900-01-01, 2300-01-01)
の範囲でカウントすることです。
date.hを使用し、これは非常に簡単かつ効率的に達成このようなものです:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
unsigned freq[7] = {};
for (auto ym = 1900_y/jan; ym < 2300_y/jan; ym += months{1})
freq[unsigned{weekday{ym/13}}]++;
for (unsigned i = 0; i < 7; ++i)
std::cout << weekday{i} << " : " << freq[i] << '\n';
}
ym
がdate::year_month
オブジェクトです。これはtime_point
のように考えることができますが、それはmonths
の非常に粗い精度を持っています。
毎年、毎月の各月をループし、その月の13日の曜日を計算し、weekday
をunsigned
にキャストするだけです。
高度な構文は非常に単純であり、読みやすいです。
フード下のアルゴリズムはdays_from_civil
とweekday_from_days
です。これらの低レベル日付アルゴリズムのいずれも反復的ではないので、非常に効率的です。つまり、読みやすい高水準の構文と高性能の両方を実現できます。
この単純なプログラムの出力も非常に読みやすいです:
Sun : 687
Mon : 685
Tue : 685
Wed : 687
Thu : 684
Fri : 688
Sat : 684
これは、13日の金曜日は少し可能性が高い他の曜日よりも判明しました。
C++では1Z(C++ 17私たちは願っています)、あなたもこれらの結果とconstexpr std::array<unsigned, 7>
(いくつかの理由は、コンパイル時に、このような数字を持っていることが重要でなければなりません)を作成することができるようになります。
このアセンブリを生成
#include "date.h"
#include <array>
#include <iostream>
constexpr
std::array<unsigned, 7>
compute_freq() noexcept
{
using namespace date;
decltype(compute_freq()) freq = {};
for (auto ym = 1900_y/jan; ym < 2300_y/jan; ym += months{1})
freq[unsigned{weekday{ym/13}}]++;
return freq;
}
constexpr auto freq = compute_freq();
int
main()
{
using namespace date::literals;
static_assert(freq[unsigned{sun}] == 687);
static_assert(freq[unsigned{mon}] == 685);
static_assert(freq[unsigned{tue}] == 685);
static_assert(freq[unsigned{wed}] == 687);
static_assert(freq[unsigned{thu}] == 684);
static_assert(freq[unsigned{fri}] == 688);
static_assert(freq[unsigned{sat}] == 684);
}
:
_freq:
.long 687 ## 0x2af
.long 685 ## 0x2ad
.long 685 ## 0x2ad
.long 687 ## 0x2af
.long 684 ## 0x2ac
.long 688 ## 0x2b0
.long 684 ## 0x2ac
そして、あなたはちょうどそれよりも効率的取得することはできません。
カノニカルが早い段階でこのような疑問を解決するための素晴らしい試み:-) ...(今日の投票では、申し訳ありません) –