factors = 126.prime_division # [[2,1], [3,2], [7,1]]
# To есть 2**1 * 3**2 * 7**1
Имеется также метод класса Integer.from_prime_division
, который восстанавливает исходное число из его сомножителей. Это именно метод класса, потому что выступает в роли «конструктора» целого числа.
factors = [[2,1],[3,1],[7,1]]
num = Integer.from_prime_division(factors) # 42
Ниже показано, как разложение на простые множители можно использовать для отыскания наименьшего общего кратного (НОК) двух чисел:
require 'mathn'
class Integer
def lcm(other)
pf1 = self.prime_division.flatten
pf2 = other.prime_division.flatten
h1 = Hash[*pf1]
h2 = Hash[*pf2]
hash = h2.merge(h1) {|key,old,new| [old,new].max }
Integer.from_prime_division(hash.to_a)
end
end
p 15.1cm(150) # 150
p 2.1cm(3) # 6
p 4.1cm(12) # 12
p 200.1cm(30) # 600
5.14. Простые числа
В библиотеке mathn
есть класс для порождения простых чисел. Итератор each
возвращает последовательные простые числа в бесконечном цикле. Метод succ
порождает следующее простое число. Вот, например, два способа получить первые 100 простых чисел:
require 'mathn'
list = []
gen = Prime.new
gen.each do |prime|
list << prime
break if list.size == 100
end
# или:
list = []
gen = Prime.new
100.times { list << gen.succ }
В следующем фрагменте проверяется, является ли данное число простым. Отметим, что если число велико, а машина медленная, то на выполнение может уйти заметное время:
require 'mathn'
class Integer
def prime?
max = Math.sqrt(self).ceil
max -= 1 if max % 2 == 0
pgen = Prime.new
pgen.each do |factor|
return false if self % factor == 0
return true if factor > max
end
end
end
31.prime? # true
237.prime? # false
1500450271.prime? # true
5.15. Явные и неявные преобразования чисел
Программисты, только начинающие изучать Ruby, часто удивляются, зачем нужны два метода to_i
и to_int
(и аналогичные им to_f
и to_flt
). В общем случае метод с коротким именем применяется для явных преобразований, а метод с длинным именем — для неявных.
Что это означает? Во-первых, в большинстве классов определены явные конверторы, но нет неявных. Насколько мне известно, методы to_int
и to_flt
не определены ни в одном из системных классов.
Во-вторых, в своих собственных классах вы, скорее всего, будете определять неявные конверторы, но не станете вызывать их вручную (если только не заняты написанием «клиентского» кода или библиотеки, которая пытается не конфликтовать с внешним миром).
Следующий пример, конечно, надуманный. В нем определен класс MyClass
, который возвращает константы из методов to_i
и to_int
. Такое поведение лишено смысла, зато иллюстрирует идею:
class MyClass
def to_i
3
end
def to_int
5
end
end
Желая явно преобразовать объект класса MyClass
в целое число, мы вызовем метод to_i
:
m = MyClass.new x = m.to_i # 3
Но при передаче объекта MyClass
какой-нибудь функции, ожидающей целое число,