Given a decimal number and a base, convert the number to n-ary base number.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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