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