Меню

Уроци

Влез Излез

Математика, програмиране и часовници

Сутрин си навивам алармата за 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).

По този начин мога да напиша 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 &lt; 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 час. Така при обиколката на цялото кълбо е с един ден по-рано (от чисто перцептуална гледна точка) отколкото е осъзнавал.

Вашият коментар

Вашият имейл адрес няма да бъде публикуван. Задължителните полета са отбелязани с *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax