Математика, програмиране и часовници
Сутрин си навивам алармата за 6:20. След което минават 10-15 минути докато най-накрая се наканя да ставам. Тази сутрин обаче беше по-особена и това заради новия ми часовник. Той всъщност не е нов – подариха ми го преди 5 месеца за именния ми ден. Едва вчера обаче, реших най-сетне да го изпробвам. Чаках толкова дълго, защото просто мразя ръчни часовници. Особено такива със стрелки.
И днес точно в 6:33 погледнах часовника си, за да разбера дали е станало крайно време да се надигам. И забелязах, че стрелките за часа и за минутите се припокриват.
Всички знаем вица за мутрата, на когото му подарили часовник. Понеже той не го познавал му казали: „Когато и двете стрелки сочат нагоре – значи е 12. Когато и двете се надолу – значи е 6:30“. И също така повечето знаем, че реално припокриване нямаме в 6:30, а малко след това. Стрелката за часа до тогава също се е отместила.
Колко пъти в деня обаче и точно в кои часове наистина двете стрелки се припокриват?
За да си отговорим на този въпрос първо ще трябва да си съставим едно елементарно математическо уравнение. След това с помощта на някой програмен език ще го решим с няколко входни параметъра. Така ще намерим всички решения, които удовлетворяват характеристиките на един часовник.
Пълно завъртане на стрелките
Първо нека започнем с това, че пълният кръг на завъртане и на двете стрелки е по 360 градуса.
От там можем лесно да изведем, че 60-те минути на по-дългата стрелка отговарят всяка по на 6 градуса завъртане.
При часовете пък не делим на 60, а на 12 и се получават по 30 градуса на час. Тази стойност обаче ще трябва да се прецизира. Вече споменахме, че завъртането на стрелката на часовете зависи и от тази на минутите. Така към 30-те градуса на час трябва да добавим и по 6 градуса на минута, но разделени на 12 – за всеки час.
За да има припокриване на стрелките, трябва ъгълът, под който са се завъртели, да е равен.
Математическо уравнение
От там излиза, че уравнението, което трябва да решим е:
6*m = 30*h + (6*m)/12
С m
съм означил минутите, а с h
– часовете.
По математика, обаче сме учили, че ако имаме две променливи, трябва да имаме система от 2 уравнения, за да намерим едно решение. Ние тук имаме само едно уравнение. В този случай това означава, че ще имаме безкрайно много решения.
Отчитайки, че часовете могат да бъдат само цели числа от 1 до 12, а минутите – цели числа от 0 до 59, вече стигаме до краен брой решения, които да отговарят и на останалите изисквания.
Така де – ние от самото начало знаехме, че има няколко такива ситуации. Ако беше само една – тя щеше да е 12:00 (примерно). Но ние знаем, че има и други припокривания на стрелките. Точно тях се опитваме на намерим.
Програмно пресмятане
С помощта на компютър можем лесно да си напишем едно script-че, което да замени m
с всяка стойност от 0 до 59. За всяка итерация на цикъла да прави вложен такъв, за часовете от 1 до 12.
Колкото и да са добри компютрите в изпълнение на множество еднотипни задачи, да го напишем по подобен начин си е чисто пилеене на ресурс.
За да опростим алгоритъма си обаче, трябва да опростим и уравнението.
Така получаваме:
6*m = 30*h + (6*m)/12
6*m = 30*h + (6/12)*m
6*m = 30*h + 0.5*m
6*m - 0.5*m = 30*h
5.5*m = 30*h
m = (30*h)/5.5
m = (30/5.5)*h
m = (60/11)*h
Представянето на 30/5.5 като 60/11 е чисто колкото да нямаме смесена дроб. Десетична дроб като знаменател в обикновена е страшно грозно!
На това му се вика да решим уравнение с две неизвестни спрямо едната.
Приемаме, че едната неизвестна е аргумент, който може да бъде подаден като входен с различни стойности. Решавайки уравнението спрямо всяка от тези стойности получаваме различен резултат за m
.
Избрах да реша за m
спрямо h
, защото h
може да има само 12 стойности, а не 60 (като m
).
Свеждане до цикъл с 12 итерации
По този начин мога да напиша script, който да изпълни един елементарен цикъл от 1 до 12. Резултатите ще са минутите, в които има съвпадение, за всеки от тези часове.
Нека само 12 часа го представим като 0. При пресмятането ще ми е по-удобно 360 градуса да го приравня на 0.
От тук насетне вече идва и самият програмен код. Тъй като последните уроци, които съм писал са за PHP ще го напиша с неговия синтаксис. Като цяло алгоритъмът е толкова елементарен, че лесно може да се препише на други езици. Най-вероятно няма да има почти никакви промени:
function get_overlapping_minutes($h) {
return 60 / 11 * $h;
}
for ($i = 0; $i < 12; $i++) {
$m = get_overlapping_minutes($i);
echo "$i:$m\n";
}
Ако изпълним script-а така обаче, получаваме следния списък с часове на припокриване на стрелките:
0:0
1:5.4545454545455
2:10.909090909091
3:16.363636363636
4:21.818181818182
5:27.272727272727
6:32.727272727273
7:38.181818181818
8:43.636363636364
9:49.090909090909
10:54.545454545455
11:60
Да игнорираме за момента 11:60, което би трябвало да е 12:00 или 0:00.
Останалите стойности на минутите са доста особени, тъй като имаме 60/11 и това води до безкрайни десетични дроби. Просто PHP в даден момент ги закръгля.
И все пак защо десетични стойности? Нали за минутите казахме, че са цели числа от 0 до 59? Защо се получава това?
Бяхме достатъчно прецизни да вземем предвид, че завъртането на стрелката на часовете зависи от минутите. Обаче не отчетохме, че завъртането на стрелката на минутите от своя страна зависи от секундите.
Допустими закръгления
За да не усложняваме излишно, нека просто закръглим минутите до най-близкото цяло число:
function get_overlapping_minutes($h) {
return round(60 / 11 * $h);
}
for ($i = 0; $i < 12; $i++) {
$m = get_overlapping_minutes($i);
echo "$i:$m\n";
}
Като изключим и 11:60 и като форматираме още малко по приятно часовете, вече получаваме списъкът с часове и минути, в които стрелките се припокриват:
00:00
01:05
02:11
03:16
04:22
05:27
06:33
07:38
08:44
09:49
10:55
Виждаме, че случаите са общо 11. Очаквахте 12, нали? За всеки час по едно. Да, ама тъй като за едно пълно завъртане на стрелката на минутите през целия циферблат, часовете минават с един напред, на 11-тото завъртане, вече са минали 12 часа и оставаме с една комбинация по-малко.
Случаят е подобен на забавната история, при който в „Около света за 80 дни“ на главния герой му остава 1 ден аванс за да изпълни пътешествието си, тъй като пътува в посока обратна на въртенето на земята и при всяка часова зона връща часовника си с 1 час. Така при обиколката на цялото кълбо е с един ден по-рано (от чисто перцептуална гледна точка) отколкото е осъзнавал.