Created
February 2, 2022 22:02
-
-
Save eduardobape/66983f605bc935c5010a0a5dd4eda787 to your computer and use it in GitHub Desktop.
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
import java.math.BigDecimal | |
import java.math.RoundingMode | |
import kotlin.math.pow | |
const val EXIT = "/exit" | |
const val BACK = "/back" | |
const val BASE_10 = 10 | |
const val MAX_LENGTH_FRACTIONAL_PART = 5 | |
const val FRACTIONAL_PART_DELIMITER = '.' | |
val symbols = ('0'..'9').plus('a'..'z') | |
fun main() { | |
val entryMessage = | |
"Enter two numbers in format: {source base} {target base} (To quit type /exit): " | |
print(entryMessage) | |
var entryInput = readln() | |
while (entryInput != EXIT) { | |
val (sourceBase, targetBase) = entryInput.split(" ").map { it.toInt() } | |
val inputNumberMessage = | |
"Enter number in base $sourceBase to convert to base $targetBase (To go back type /back): " | |
print(inputNumberMessage) | |
var numberToConvert = readln() | |
while (numberToConvert != BACK) { | |
println( | |
"Conversion result: ${ | |
convertNumberFromBaseToBase( | |
numberToConvert, | |
sourceBase, | |
targetBase | |
) | |
}" | |
) | |
println() | |
print(inputNumberMessage) | |
numberToConvert = readln() | |
} | |
println() | |
print(entryMessage) | |
entryInput = readln() | |
} | |
} | |
fun convertNumberFromBaseToBase(numberToConvert: String, sourceBase: Int, targetBase: Int): String { | |
val integerPartInBase10 = convertIntegerPartToBase10(numberToConvert, sourceBase) | |
val fractionalPartInBase10 = convertFractionalPartToBase10(numberToConvert, sourceBase) | |
val numberInBase10 = integerPartInBase10 + fractionalPartInBase10 | |
val integerPartInTargetBase = | |
convertIntegerPartFromBase10ToTargetBase(numberInBase10, targetBase) | |
val fractionalPartInTargetBase = | |
convertFractionalPartFromBase10ToTargetBase(numberInBase10, targetBase) | |
val convertedNumber = if (fractionalPartInTargetBase != "") { | |
"$integerPartInTargetBase.$fractionalPartInTargetBase" | |
} else { | |
integerPartInTargetBase | |
} | |
return convertedNumber | |
} | |
fun convertIntegerPartToBase10(sourceNumber: String, sourceBase: Int): BigDecimal { | |
val truncatedSourceNumber = sourceNumber.substringBefore(FRACTIONAL_PART_DELIMITER, sourceNumber) | |
if (sourceBase != BASE_10) { | |
var convertedIntegerPart = BigDecimal.ZERO | |
val reversedIntegerPart = truncatedSourceNumber.reversed() | |
for (i in reversedIntegerPart.indices) { | |
convertedIntegerPart += BigDecimal( | |
(mapSymbolToNumber(reversedIntegerPart[i]) * sourceBase.toDouble().pow(i)).toString() | |
) | |
} | |
return convertedIntegerPart.setScale(0, RoundingMode.DOWN) | |
} | |
return BigDecimal(truncatedSourceNumber) | |
} | |
fun convertFractionalPartToBase10(sourceNumber: String, sourceBase: Int): BigDecimal { | |
var convertedFractionalPart: BigDecimal | |
if (!sourceNumber.contains(FRACTIONAL_PART_DELIMITER)) { | |
convertedFractionalPart = BigDecimal.ZERO | |
} else { | |
if (sourceBase == BASE_10) { | |
convertedFractionalPart = BigDecimal(sourceNumber).remainder(BigDecimal.ONE) | |
} else { | |
convertedFractionalPart = BigDecimal.ZERO | |
val fractionalPartWithoutPoint = sourceNumber.substringAfter(FRACTIONAL_PART_DELIMITER, "0") | |
for (i in fractionalPartWithoutPoint.indices) { | |
convertedFractionalPart += BigDecimal( | |
(mapSymbolToNumber(fractionalPartWithoutPoint[i]) * sourceBase.toDouble().pow(-(i + 1))).toString() | |
) | |
} | |
} | |
} | |
return convertedFractionalPart | |
} | |
fun convertIntegerPartFromBase10ToTargetBase(sourceNumber: BigDecimal, targetBase: Int): String { | |
val truncatedSourceNumber = sourceNumber.setScale(0, RoundingMode.DOWN) | |
if (targetBase != BASE_10) { | |
val remainders = mutableListOf<Char>() | |
var quotation = truncatedSourceNumber | |
var remainder: BigDecimal | |
while (quotation > BigDecimal.ZERO) { | |
remainder = quotation % targetBase.toBigDecimal() | |
remainders.add(0, mapNumberToSymbol(remainder.toInt())) | |
quotation = quotation.divide(targetBase.toBigDecimal(), RoundingMode.DOWN) | |
} | |
return ( | |
if (truncatedSourceNumber == BigDecimal.ZERO) truncatedSourceNumber.toString() | |
else remainders.joinToString("") | |
) | |
} | |
return truncatedSourceNumber.toString() | |
} | |
fun convertFractionalPartFromBase10ToTargetBase(sourceNumber: BigDecimal, targetBase: Int): String { | |
var fractionalPartFromBase10 = sourceNumber.remainder(BigDecimal.ONE) | |
var fractionalPartTargetBase = "" | |
if (fractionalPartFromBase10 != BigDecimal.ZERO) { | |
if (targetBase == BASE_10) { | |
fractionalPartTargetBase = fractionalPartFromBase10.toString().substringAfter(FRACTIONAL_PART_DELIMITER).take(MAX_LENGTH_FRACTIONAL_PART) | |
} else { | |
val symbolsConvertedNumber = mutableListOf<Char>() | |
var lengthFractionalPart = 0 | |
while (fractionalPartFromBase10 > BigDecimal.ZERO && lengthFractionalPart < MAX_LENGTH_FRACTIONAL_PART) { | |
val integerPart = (fractionalPartFromBase10 * targetBase.toBigDecimal()).setScale(0, RoundingMode.DOWN) | |
symbolsConvertedNumber.add(mapNumberToSymbol(integerPart.toInt())) | |
fractionalPartFromBase10 = fractionalPartFromBase10 * targetBase.toBigDecimal() - integerPart | |
lengthFractionalPart++ | |
} | |
fractionalPartTargetBase = symbolsConvertedNumber.joinToString("") | |
} | |
if (fractionalPartTargetBase.length < MAX_LENGTH_FRACTIONAL_PART) { | |
fractionalPartTargetBase += "0".repeat(MAX_LENGTH_FRACTIONAL_PART - fractionalPartTargetBase.length) | |
} | |
} | |
return fractionalPartTargetBase | |
} | |
fun mapSymbolToNumber(symbol: Char): Int { | |
return symbols.indexOf(symbol) | |
} | |
fun mapNumberToSymbol(number: Int): Char { | |
return symbols.elementAt(number) | |
} | |
/* | |
Test cases: | |
Enter two numbers in format: {source base} {target base} (To quit type /exit) > 10 7 | |
Enter number in base 10 to convert to base 7 (To go back type /back) > 0.234 | |
Conversion result: 0.14315 | |
Enter number in base 10 to convert to base 7 (To go back type /back) > 10.234 | |
Conversion result: 13.14315 | |
Enter number in base 10 to convert to base 7 (To go back type /back) > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit) > 35 17 | |
Enter number in base 35 to convert to base 17 (To go back type /back) > af.xy | |
Conversion result: 148.g88a8 | |
Enter number in base 35 to convert to base 17 (To go back type /back) > aaaa.0 | |
Conversion result: 54e36.00000 | |
Enter number in base 35 to convert to base 17 (To go back type /back) > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit) > 21 10 | |
Enter number in base 21 to convert to base 10 (To go back type /back) > 4242 | |
Conversion result: 38012 | |
Enter number in base 21 to convert to base 10 (To go back type /back) > 4242.13a | |
Conversion result: 38012.05550 | |
Enter number in base 21 to convert to base 10 (To go back type /back) > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 5 | |
Enter number in base 2 to convert to base 5 (To go back type /back): > 11101001.00000 | |
Conversion result: 1413.00000 | |
Enter number in base 2 to convert to base 5 (To go back type /back): > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 8 | |
Enter number in base 2 to convert to base 8 (To go back type /back): > 1101111000.10000 | |
Conversion result: 1570.40000 | |
Enter number in base 2 to convert to base 8 (To go back type /back): > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 11 | |
Enter number in base 2 to convert to base 11 (To go back type /back): > 111111.11000 | |
Conversion result: 58.83838 | |
Enter number in base 2 to convert to base 11 (To go back type /back): > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 14 | |
Enter number in base 2 to convert to base 14 (To go back type /back): > 1000100.00000 | |
Conversion result: 4c.00000 | |
Enter number in base 2 to convert to base 14 (To go back type /back): > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 17 | |
Enter number in base 2 to convert to base 17 (To go back type /back): > 1010011.00000 | |
Conversion result: 4f.00000 | |
Enter number in base 2 to convert to base 17 (To go back type /back): > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 20 | |
Enter number in base 2 to convert to base 20 (To go back type /back): > 101010111.10000 | |
Conversion result: h3.a0000 | |
Enter number in base 2 to convert to base 20 (To go back type /back): > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 23 | |
Enter number in base 2 to convert to base 23 (To go back type /back): > 1010010011.10000 | |
Conversion result: 15f.bbbbb | |
Enter number in base 2 to convert to base 23 (To go back type /back): > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 26 | |
Enter number in base 2 to convert to base 26 (To go back type /back): > 1000011101.01000 | |
Conversion result: kl.6d000 | |
Enter number in base 2 to convert to base 26 (To go back type /back): > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 29 | |
Enter number in base 2 to convert to base 29 (To go back type /back): > 100011001.00000 | |
Conversion result: 9k.00000 | |
Enter number in base 2 to convert to base 29 (To go back type /back): > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 32 | |
Enter number in base 2 to convert to base 32 (To go back type /back): > 1001100111.10000 | |
Conversion result: j7.g0000 | |
Enter number in base 2 to convert to base 32 (To go back type /back): > /back | |
Enter two numbers in format: {source base} {target base} (To quit type /exit): > 2 35 | |
Enter number in base 2 to convert to base 35 (To go back type /back): > 100001110.01000 | |
Conversion result: 7p.9q9q9 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment