Детерминированное преобразование оснований с помощью логарифмов


Введение

В этой статье рассматривается несколько решений задачи кодирования конвертера десятичных чисел в восьмеричные, написанной на языке 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.

Оцените статью
Procodings.ru
Добавить комментарий