月の日数を計算するための式

:この投稿は、記事cmcenroe.me/2014/12/05/days-in-month-formula.htmlパートI )の翻訳であり、著者の補足( パートII )です。 材料を真剣に受け取らないでください。むしろ、算数の学校知識以上を必要とせず、実践的な応用を持たない心のトレーニングとして。 素敵な読書を!

パートI


エントリー


最近、眠れない夜を過ごした後、私は一年の各月の日数を記憶する方法を考えてきました。 これを行うには、カウントと、指の関節を頼りにする方法がありますが、どちらも私に適していない。 そのような問題を解決するための数式はあるのだろうかと思いました-そのような大まかな研究を発見していないので、私はそれを作成することに挑戦しました。

言い換えると、1〜12の数値で表される各月xの値f(x)がその月の日数に等しくなるような関数fを見つける必要があります。 引数と関数値の表1
x123456789101112
f(x)312831303130313130313031

あなたが私の決定を読む前に自分で試してみたいという欲求があるなら、今がその時です。 完成した回答をすぐに見たい場合は、ネタバレをご覧ください。
答え

以下は、解決策を見つけるための私の手順です。

数学的装置


まず、この問題を解決するための2つの重要な演算子である整数除算と除算の残りのメモリのクイックリフレッシュ。

整数除算は、2つの整数を除算し、商から小数部分を破棄するときに多くのプログラミング言語で使用される演算子です。 私は彼を 。 例:

除算の余りは、除算の余りを見つける演算子です。 多くのプログラミング言語は記号を使用しますが、フォームの構造を使用します 例えば:

部門の残りは部門と同じ優先順位を持っていることに注意してください。

基本


したがって、基本的な式を取得するために、数学的な装置を適用します。 2通常の月である30日または31日。 順番に1または0を取得し、この数値に定数を追加します。

テーブルを取得すると、正しい値が太字で強調表示されます。
x123456789101112
f(x)313031303130313031303130

いいスタートです! すでに1月と3月から7月までの月の正しい値があります。 2月は特別なケースであり、少し後で対処します。 7月以降、残りの月については、0と1の受け取り順序を逆にする必要があります。
これを行うには、割り切れる1に追加します。

x123456789101112
f(x)303130313031303130313031

現在、正しい値は8月から12月までですが、予想どおり、他の月の値は正しくありません。 これらの式をどのように組み合わせることができるか見てみましょう。

マスクオーバーレイ


これには区分的に定義された関数が必要ですが、私には退屈そうに思えたので、ある区間で関数の一部を使用し、別の区間で別の部分を使用する別のソリューションパスについて考えました。
1つのアプリケーション領域で1、残りの領域で0に等しい式を見つけるのが最も簡単だと思います。 引数に式を乗算することにより、アプリケーションの範囲外の式から引数を除外する方法。この動作はビットマスクに似ているため、「マスキング」と呼ばれます。
このメソッドを関数の最後の部分に適用するには、1に等しい式を見つける必要があります 、および-引数は常に16未満であるため、これには8による整数除算が最適です。
x123456789101112
⌊x ⁄ 8⌋000000011111

今、このマスクを割り切れる 表現 1の代わりに、0と1の式を取得する順序を反対に置き換えることができます。

x123456789101112
f(x)313031303130313130313031

ユーレカ! 2月以外はすべて正しいです。 サプライズサプライズ。

2月


毎月、30日または31日。ただし、2月28日から2月を除きます(うるう年はこのタスクの範囲外です)。 3現時点では、式によると30日間あるため、2に等しい式を減算すると良いでしょう
私が思いついたのは最高です 2月以降のすべての月のマスク:
x123456789101112
2 mod x002222222222

残りの月に2を追加して基本定数を28に変更すると、式が得られます。

x123456789101112
f(x)29日2831303130313130313031

残念ながら、1月は2日短くなりました。 しかし、幸いなことに、最初の1か月のみに適用される式を取得するのは非常に簡単です。 数。 2を掛けると、最終的な式が得られます。

x123456789101112
f(x)312831303130313130313031


あとがき


これは、単純な算術を使用して、年の任意の月の日数を取得するための式です。 次回9月の何日かを思い出したら、 JavaScriptで次の1行関数を使用します。

function f(x) { return 28 + (x + Math.floor(x/8)) % 2 + 2 % x + 2 * Math.floor(1/x); } 

パートII


エントリー


最初の部分では、短くてわずかにエレガントな式が得られました。その主な利点は、数学的装置の単純さ、分岐と条件式の欠如、および簡潔性です。 欠点は、プロジェクトに適用しないという事実に加えて、うるう年ではなくうるう年の検証がないことです。
したがって、1〜12の数字と0より大きいy年で表される各月xの値f(x、y)y年の x月の日数と等しくなるように、関数fを作成するタスクを自分で設定します。
せっかちな人のために、ネタバレの下に既製の答えがありますが、私は残りの人に私に従ってください。
答え


除算の剰余: modおよび⌊⌋


視覚的にわかりやすくするために、一部の式では、残りの除算演算子が必要に応じて下括弧で置き換えられていることに同意します。


うるう年


うるう年に追加のカレンダー日が導入されます:2月29日。 ご存知のように、うるう年は4の倍数であり、100の倍数でも400の倍数でもありません。このステートメントと同じ式を記述します。



この式を代数的にするには、式の結果に適用する必要があります タイプインジェクション:


これにより、月の日数を決定する式で使用するために、剰余なしで除算する場合は1を、剰余で除算する場合は0を取得できます。

関数g 'として、1-除算の剰余を使用できます のために
x01234567891011121314
g '(x)無限大10000000000000

配当と除数を1増やすと、正しい公式が得られることが簡単にわかります。
x01234567891011121314
g '(x)100000000000000


したがって、式 私たちは次のように書きます:

そして、表現 私たちは次のように書きます:


このアプローチを使用して、次の関数g(y)を取得します。その年の値はうるう年の場合は1、そうでない場合は0になります。

y19901991199219931994199519961997199819992000年
g(y)00100010001
y2000年2100220023002400250026002700280029003000
g(y)10001000100

太字はle年です。

受け入れられた合意の枠組み内で、部門の残りを取得する演算子はmodとbothの両方で表現できることを思い出してください。

マスクオーバーレイ


式で の一部 1月に2日を追加する修正です。 係数2を削除し、分子の1を2に置き換えると、この式は1月に2日、2月に1日を追加します。これにより、うるう年に日を追加するためのキーが得られます。 明確にするために、式で中間値g(y)を使用し、 yとして2000(うるう)年と2001(うるうではない)年を使用します。

x123456789101112
f(x、2000)3129日31303130313130313031
f(x、2001)302831303130313130313030

1月を除くすべての月の値はうるう年ではありません。

この厄介な誤解を修正するために、1月1日までに、すでに知っている式を追加します。

x123456789101112
f(x、2000)3229日31303130313130313031
f(x、2001)312831303130313130313030


うるう年の場合、1月から1日を差し引く必要があります。これは、 x 、そして

次に、式は次の形式を取ります。


または:

x123456789101112
f(x、2000)3129日31303130313130313031
f(x、2001)312831303130313130313030

おわりに


その結果、特定の年の月の日数を取得するために使用できる、はるかにかさばるがより普遍的な式が得られました。

 function f(x, y) { return 28 + ((x + Math.floor(x / 8)) % 2) + 2 % x + Math.floor((1 + (1 - (y % 4 + 2) % (y % 4 + 1)) * ((y % 100 + 2) % (y % 100 + 1)) + (1 - (y % 400 + 2) % (y % 400 + 1))) / x) + Math.floor(1/x) - Math.floor(((1 - (y % 4 + 2) % (y % 4 + 1)) * ((y % 100 + 2) % (y % 100 + 1)) + (1 - (y % 400 + 2) % (y % 400 + 1)))/x); } 

C# ideone.com/fANutzの例。


1 私はそのようなニーモニックの使い方を知らないので、インターネット上のプレートを見ました。
2 。 ほとんどのルールと同様に、「基本」または「多くの例外を伴うルール」。
。 2月はもともとローマ暦の年の最後の月であったため、論理は他の誰よりも短いということです。 年末に日を追加または削除するロジックもあるため、その長さは可変です。

更新しました。 1:
VKontakteコミュニティの最初の部分の代替翻訳。
更新しました。 2: kexmenのコメントのおかげで、うるう年( g(y) )を決定する式のバグが修正され、最終的な式が修正されました。

Source: https://habr.com/ru/post/J261773/


All Articles