Instantly share code, notes, and snippets.

Embed
What would you like to do?
Given a decimal number and a base, convert the number to n-ary base number.
<?php
/**
* Given a decimal number and a base, convert the number to n-ary base number. Also find a way to perform arithmetic
* operations. The n is actually 36, however the principal is same.
*
* To perform arithmetic operations, we convert the number back to decimal, do the math, then convert back to the
* original base.
*/
/**
* Convert given number to the base.
*
* @param int $number Decimal number
* @param int $base which base, max allowed is 36, 10 + 26 alphabets
* @return string resulting number, could be hex so return type is string
*/
function convert(int $number, int $base): string
{
if ($base > 36) {//Can't do
return '💻 LOAD LETTER' . PHP_EOL;
}
//http://php.net/ord, Rather than maintaining a list of chars, just using in built functions to get Alphabets.
$offset = ord('A') - 1;
$result = [];
while ($number >= $base) {
if (($number % $base) === 0) {
$result[] = '0';
$number = ($number / $base); // 32 / 2 -> 16
} else {
$result [] = ($number % $base); // 17 % 16 -> 1
$number = intval($number / $base); // 17 / 16 -> 1
}
}
if ($number < $base) {
$result[] = $number;
}
if ($base > 9) { //15
for ($i = 0; $i < count($result); $i++) {
if ($result[$i] > 9) {
//http://php.net/chr, get the corresponding alphabet.
$result[$i] = chr(($offset + ($result[$i] - 9)));
}
}
}
//reverse the array
$reversed = array_reverse($result);
return implode("", $reversed);
}
/**
* Convert the given number in the base to decimal representation.
*
* @param string $number can be hex number so using string type
* @param int $base which base, max allowed is 36, 10 + 26 alphabets
* @return string resulting decimal number
*/
function convertToDecimal(string $number, int $base): string
{
if ($base > 36) {
return '💻 LOAD LETTER' . PHP_EOL;
}
$reversed = strrev($number);
$offset = ord('A') - 1 + 9;
$result = 0;
for ($i = 0; $i < strlen($reversed); $i++) {
if (ctype_alpha($reversed[$i])) {
$digit = ord($reversed[$i]) - $offset;
} else {
$digit = $reversed[$i];
}
$result = $result + ($base ** $i) * $digit; // 16 + 64 + 256
}
return ($result);
}
/**
* Add
*
* @param string $number1
* @param string $number2
* @param int $base
* @return string
*/
function add(string $number1, string $number2, int $base): string
{
return convert((convertToDecimal($number1, $base) + convertToDecimal($number2, $base)), $base);
}
/**
* Subtract
*
* @param string $number1
* @param string $number2
* @param int $base
* @return string
*/
function subtract(string $number1, string $number2, int $base): string
{
return convert((convertToDecimal($number1, $base) - convertToDecimal($number2, $base)), $base);
}
/**
* Multiply.
*
* @param string $number1
* @param string $number2
* @param int $base
* @return string
*/
function multiply(string $number1, string $number2, int $base): string
{
return convert((convertToDecimal($number1, $base) * convertToDecimal($number2, $base)), $base);
}
/**
* Divide.
*
* @param string $number1
* @param string $number2
* @param int $base
* @return string
*/
function divide(string $number1, string $number2, int $base): string
{
return convert((convertToDecimal($number1, $base) / convertToDecimal($number2, $base)), $base);
}
//Let us test
$testcases = [
[3, 2],
[4, 2],
[5, 3],
[6, 3],
[35, 4],
[38, 5],
[3, 6],
[21, 7],
[22, 7],
[3, 8],
[32, 8],
[33, 8],
[3, 10],
[30, 10],
[31, 10],
[32, 12],
[36, 12],
[16, 16],
[331, 2],
[332, 3],
[333, 16],
[336, 16],
[336, 36],
[336, 37],
];
foreach ($testcases as $testcase) {
$converted = convert($testcase[0], $testcase[1]);
$reverted = convertToDecimal($converted, $testcase[1]);
$base_converted = strtoupper(base_convert($testcase[0], 10, $testcase[1]));
echo 'Decimal: ' . $testcase[0] . ' Base: ' . $testcase[1] . ' Converted: ' . $converted . ' == ' . $base_converted . '? ' . ($converted === $base_converted ? '' : '') . PHP_EOL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment