Як однією математичною формулою по номеру місяця порахувати кількість днів в нім?


Дізнайтесь більше про нові кар'єрні можливості в EchoUA. Цікаві проекти, ринкова оплата, гарний колектив. Надсилайте резюме та приєднуйтеся до нас.

Розповідає Куртис МакЭнрое


Нещодавно після тривалого часу, проведеного без сну, я замислився над тим, як можна упізнати кількість днів в місяці, знаючи його номер. Існують дитячі вірші на цю тему, є спосіб підрахунку по кісточках, але ці методи не влаштовують мене – я занурився в пошук математичної формули, яку і вивів через деякий час.

Отже, завдання

Формально Іншими словами, нам треба отримати функцію f (x), яка б давала наступний список значень (який я, до речі кажучи, знайшов десь в інтернеті, а не вивів за допомогою мнемонічних правил) :

Варто врахувати, що в якості аргументу ми отримуємо тільки номер місяця, тобто ми не враховуємо високосні роки, і f (2) = 28.

Якщо ви хочете упізнати отриманий мною результат, пролистните до кінця цієї сторінки. Те, що буде описано далі – це виведення шуканої формули.

Чим ми користуватимемося

Окрім складання, віднімання і множення, я скористаюся двома операціями: цілочисельним діленням і операцією узяття залишку. Нагадаю, що це таке :

  • Цілочисельне ділення, чи “ділення з округленням вниз”. У мене воно буде представлено, як звичайне ділення: a / b – маючи на увазі ⌊a / b⌋. Наприклад, 5 / 3 = 1.
  • Узяття залишку по модулю. Позначу традиційно ділення із залишком: a % b = a - (a / b) * b. Наприклад, 5 % 3 = 2.

Вони мають однаковий пріоритет і являються левоассоциативными.

Основи, або Правило з множиною виключень

Давайте спробуємо знайти таку закономірність, яка задовольнила б як можна більшій кількості значень аргументу. Звичайна кількість днів в місяці коливається між 30 і 31. При цьому, можна помітити залежність цього числа від парності місяця – значить, скористаємося операцією узяття залишку по модулю 2. Здається, це повинно бути щось, ніби:

f₁ (x) = 30 + x%2


Непоганий старт! Не звертаючи уваги на лютий, для якого явно доведеться піти на якісь хитрощі, порадіємо тому, що ми змогли підігнати функцію під першу половину року. А далі, починаючи з серпня, парність потрібно змінити на протилежну. Зробити це можна, замінивши x%2 у першому варіанті формули на (x+1)%2:

f₂ (x) = 30 + (x + 1) % 2


Як і очікувалося, тепер перша половина року вже поза областю правильних значень, зате місяці з серпня по грудень дали те, що потрібно. Знайдемо спосіб об’єднати дві ці частини.

Маска

Нам треба, щоб +1 в ділимому ” активувалося” тільки при досягненні аргументом значень, великих 8, тобто нам необхідно застосувати деяку маску. При цьому значення аргументу не можуть перевершувати 12. Значить, нам ідеально підійде цілочисельне ділення аргументу на 8:


Рівно як нам і треба. Скористаємося цим виведенням:

f₃ (x) = 30 + (x + x / 8) % 2


Юшку! Все правильно, окрім лютого. Як несподівано.

Лютий

У усіх місяцях 30 або 31 день, в лютому ж – 28 (нагадаю, ми не розглядаємо високосні роки).

Історична довідка: у романському календарі лютий був останнім місяцем року – погодитеся, додавання одного дня у високосні роки в кінець календаря інтуїтивно зрозуміліше. Проте ми користуємося григоріанським календарем, в якому найкоротший місяць перенесений ближче до початку по волі одного з мудрих правителів.

У самій останній версії нашої формули лютому дісталися цілих 30 днів. А тому нам треба відсікти у нього пару днів. Природно, від цього постраждають і ще якісь місяці: або зліва від лютого, або праворуч від нього в нашому списку – проте, справа місяців значно менше, тому нам доведеться пожертвувати саме січнем, потім підправивши формулу і для нього. Відсікти дні для першого і другого місяців можна за допомогою вираження 2%x:

Тоді наша формула набирає вже наступного вигляду:

f₄ (x) = 28 + (x + x / 8) % 2 + 2 % x

Залишився останній крок – підлатати січень. Це зробити не так складно: просто додамо 2 дні тільки до нього, тобто до такого місяця, чий номер менше або дорівнює одиниці. Як вам ідея використати для цієї мети 1/x? Перевіряємо:

f₅ (x) = 28 + (x + x / 8) % 2 + 2 % x + 1 / x * 2


Бінго! 12 з 12!

Висновок

Отже, ми вивели шукану формулу, ось вона, записана на мові,JavaScript:

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

Запитайте мене, скільки днів у вересні? Я скажу вам: f (9).

Переклад статті “A Formula for the Number of Days in Each Month”

Київ, Харків, Одеса, Дніпро, Запоріжжя, Кривий Ріг, Вінниця, Херсон, Черкаси, Житомир, Хмельницький, Чернівці, Рівне, Івано-Франківськ, Кременчук, Тернопіль, Луцьк, Ужгород, Кам'янець-Подільський, Стрий - за статистикою саме з цих міст програмісти найбільше переїжджають працювати до Львова. А Ви розглядаєте relocate?


Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *