Введение
В этой статье рассматривается несколько решений задачи кодирования конвертера десятичных чисел в восьмеричные, написанной на языке ruby.
Примечание: Эти решения можно обобщить для преобразования десятичных чисел в любые основания меньше 10, добавив второй параметр функции и заменив все 8 на заданный параметр.
Решение 1: Стандартный способ
Один из простых способов преобразования оснований заключается в многократном взятии по модулю входного числа и целевого основания num % 8
, затем деление входного числа на целевое основание num /= 8
, пока число не станет пустым while num > 0
. Каждый результат модуляции либо добавляется в массив, либо суммируется в результирующее число, как в примере ниже.
def octal_convertor(num)
octal = 0
i = 1
while num > 0
octal += (num % 8) * i
num /= 8
i *= 10
end
return octal
end
В этом решении используется переменная i = 1
, которая увеличивается на i *= 10
на каждой итерации. Она используется для умножения num % 8
, так что она переходит на следующее место целого числа в octal += (num % 8) * i
. Это можно представить себе как вырезание цифр основания 8 из num
и вставка их в следующее место целого числа в octal
.
Решение 2: Детерминированная итерация с логарифмом
Количество мест (цифр) в целом числе по любому основанию (в данном случае по основанию 8) можно вычислить с помощью Math.log(num,8).floor + 1
. Это покажет, сколько цифр нужно «вырезать» из числа num % 8
, или, скорее, количество необходимых итераций цикла. Таким образом, нет необходимости проверять, что num > 0
, мы можем просто запустить цикл точное количество раз.
def octal_convertor(num)
octal = 0
(Math.log(num,8).floor + 1).times do |i|
octal += (num % 8) * 10**i
num /= 8
end
return octal
end
Метод .times
принимает блок и передает счетчик итераций в |i|
. Таким образом, помимо того, что переменная ‘i’ в предыдущих решениях заранее знает точное количество итераций, она обеспечивается методом .times
. |i|
увеличивается от нуля, поэтому для того, чтобы вставить восьмеричные цифры в нужное место (num % 8)
умножается на 10**i
.
Решение 3: Число как массив
Это решение работает так же, как и выше, но создает новый массив с длиной восьмеричного числа (так что для каждой восьмеричной цифры найдется свое место). Подобно .times
Array.new
принимает блок, в котором вы можете заполнить каждое значение в массиве чем-либо, этот блок принимает значение индекса |i|
.
def octal_convertor(num)
Array.new(Math.log(num,8).floor + 1) {|i| ((num / 8**i) % 8) * 10**i }.sum
end
num
не делится взаимно однозначно num /= 8
, вместо этого, используя ‘i’, мы вычисляем, сколько раз оно должно было делиться num / 8**i
или, точнее, на каком восьмеричном месте находится текущая итерация. 10**i
работает точно так же, как и ранее. Теперь массив содержит все восьмеричные цифры, умноженные на 10**i
, что обеспечивает правильное количество добавленных нулей, поэтому при суммировании они помещаются в нужное место. .sum
складывает все числа в массиве вместе, возвращая преобразованное число.
Заключение
Вычисление длины цифр числа с помощью логарифмов дает возможность заранее определить количество итераций и перебирать перечислимые объекты (массивы, числа) вместо использования циклов while.