Трета задача
- Краен срок:
- 26.10.2015 17:30
- Точки:
- 6
Срокът за предаване на решения е отминал
Математически безполезности
Когато ги тресе липсата на вдъхновение, преподавателите по програмиране много обичат да дават задачи с някаква "математика" в тях - факториели, фибоначита и прочее. Когато липсата мине на стероиди, резултатът е тази задача.
В нея ще упражните употребата и имплементацията на класове, миксиращи
Enumerable
. Огледайте внимателно документацията на модула, понеже има методи,
които ще ви бъдат полезни.
Три поредици
Дефинирайте класове за следните три поредици.
RationalSequence
Знаете ли, че между рационалните числа и естествените числа може да се построи биекция? С други думи (и много неточност), има "толкова" естествени числа, "колкото" и рационални (реалните, за сметка на това, са "повече"). Първата поредица ще ви помогне да осмислите как става.
sequence = RationalSequence.new(4)
sequence.to_a # => [(1/1), (2/1), (1/2), (1/3)]
Класът RationalSequence
приема един аргумент, който определя колко
рационални числа се съдържат в тази поредица. Поредицата трябва да е подредена
по следния начин:
Обърнете внимание, че всяко рационално число присъства само веднъж - 2/2 е същото като 1/1 и се изпуска. За целите на тази задача, ще приемем, че всички рационални числа са подредени така.
(За да сме съвсем точни, ако искаме да изброим всички рационални числа, можем
да започнем от нула и да редуваме знаци - [0, (1/1), -(1/1), (2/1), -(2/1)]
,
но това не ни интересува в тази задача.)
PrimeSequence
Създайте подобна поредица, само за прости числа:
sequence = PrimeSequence.new(5)
sequence.to_a # => [2, 3, 5, 7, 11]
FibonacciSequence
И понеже няма как да се мине без Фибоначи, създайте и една последователност за него:
sequence = FibonacciSequence.new(5)
sequence.to_a # => [1, 1, 2, 3, 5]
Добавете възможност първите два аргумента в редицата на Фибоначи да се подават като аргументи с ключови думи.
sequence = FibonacciSequence.new(5, first: 0, second: 1)
sequence.to_a # => [0, 1, 1, 2, 3]
Въпреки, че е синтактично възможно, няма да тестваме какво става, ако е подаден
само един от двата аргумента first
или second
. Това е недефинирано
поведение, което може да имплементирате както искате, или да не се грижите за
това изобщо.
Три безполезни функции
Нека да използваме тези поредици, за да дефинираме няколко функции.
В Ruby не е добра практика да се дефинират top-level методи. Вместо това,
хубаво е всеки дефиниран метод да се постави в клас или модул. Създайте един
такъв модул, който, поради липса на смисъл, кръстете DrunkenMathematician
.
Ето как може да се дефинира:
module DrunkenMathematician
module_function
def answer
42
end
end
DrunkenMathematician.answer # => 42
Извикването на module_function
позволява всички функции, дефинирани в модула,
да могат да се извикват директно върху самия модул (подобно на статични функции
в C++ и Java), без да има нужда да миксираме модула в клас и да инстанцираме
класа.
Функциите, които ще трябва да дефинирате в него, са:
meaningless
Приема един аргумент n
. Функцията взима първите n рационални числа и ги
разделя на две групи:
- група 1, съдържаща рационални числа, чиито числител или знаменател е прост
- група 2, която съдържа такива рационални числа, на които нито числителят, нито знаменателят са прости
Функцията връща произведението на първата група, разделено на произведението на втората група.
# първите шест рационални числа: 1/1, 2/1, 1/2, 1/3, 3/1, 4/1
# група 1: 2/1, 1/2, 1/3, 3/1
# група 2: 1/1, 4/1
DrunkenMathematician.meaningless(6) # => (1/4)
aimless
Приема един аргумент n
. Функцията:
- взема първите n прости числа
- разделя ги на двойки
- прави рационално число от всяка двойка, като ползва първото за числител и второто за знаменател
- ако n е нечетно, знаменателят на последното число е 1
- връща сумата на тези числа
# първите четири числа са: 2, 3, 5, 7
# обърнати до рационални: 2/3, 5/7
# сумата им: 29/21
DrunkenMathematician.aimless(4) # => (29/21)
worthless
Нека наречем последователността от първите x рационални числа "отрязък". Така
например, RationalSequence.new(4)
ни връща отрязък с първите 4 рационални
числа, а RationalSequence.new(10)
- с първите 10.
Напишете функция DrunkenMathematician.worthless(n)
, приемаща един аргумент
n
. Тя трябва да връща масив, съдържащ най-големия отрязък на рационалните
числа, сумата на които не надвишава n-тото число на Фибоначи.
DrunkenMathematician.worthless(5) # => [(1/1), (2/1), (1/2), (1/3)]
Разни уточнения
- Направете всичко да работи добре с аргумент 0. Множеството на първите 0 рационални числа е празното множество. Произведението на 0 числа е 1. Сумата на 0 числа е 0.
- Ако си добавите
#prime?
метод в числата, решението може да стане по-простичко. Вие преценете в кой клас/модул да го добавите. Това е единственият monkey patch, който ви разрешаваме. - Никой от
*Sequence
класовете не трябва да изчислява резултатите си предварително. Например,RationalSequence.new(10_000)
не трябва да конструира масив с 10 000 елемента – вместо това трябва да ги генерира един по един. - Всички
*Sequence
класове трябва да миксиратEnumerable
. - Тази задача има няколко възможни решения. Вие преценете кое да използвате.
Ограничения
Тази задача има следните ограничения:
- Най-много 100 символа на ред
- Най-много 15 реда на метод
- Най-много 2 нива на влагане
Ако искате да проверите дали задачата ви спазва ограниченията, следвайте инструкциите в описанието на хранилището за домашните.
Няма да приемаме решения, които не спазват ограниченията. Изпълнявайте rubocop
редовно, докато пишете кода. Ако смятате, че rubocop
греши по някакъв начин,
пишете ни на fmi@ruby.bg, заедно с прикачен код или линк към такъв като
private gist. Ако пуснете кода си публично (например във форумите), ще смятаме
това за преписване.