n = 36.gcd2(120) # 12 k = 237.gcd2(79) # 79
Метод prime_division
выполняет разложение на простые множители. Результат возвращается в виде массива массивов, в котором каждый вложенный массив содержит простое число и показатель степени, с которым оно входит в произведение.
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
В библиотеке 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
какой-нибудь функции, ожидающей целое число, будет неявно вызван метод to_int
. Предположим, к примеру, что мы хотим создать массив с известным начальным числом элементов. Метод Array.new
может принять целое, но что если вместо этого ему будет передан объект MyClass
?
m = MyClass.new
a = Array.new(m) # [nil,nil,nil,nil,nil]
Как видите, метод new
оказался достаточно «умным», чтобы вызвать to_int
и затем создать массив из пяти элементов.
Дополнительную информацию о поведении в другом контексте (строковом) вы найдете в разделе 2.16. См. также раздел 5.16.
5.16. Приведение числовых значений
Приведение можно считать еще одним видом неявного преобразования. Если некоторому методу (например, +
) передается аргумент, которого он не понимает, он пытается привести объект, от имени которого вызван, и аргумент к совместимым типам, а затем сложить их. Принцип использования метода coerce в вашем собственном классе понятен из следующего примера:
class MyNumberSystem
def +(other)
if other.kind_of?(MyNumberSystem)
result = some_calculation_between_self_and_other
MyNumberSystem.new(result)
Читать дальше
Конец ознакомительного отрывка
Купить книгу