Skip to content

Instantly share code, notes, and snippets.

@eduardobape
Created February 2, 2022 22:02
Show Gist options
  • Save eduardobape/66983f605bc935c5010a0a5dd4eda787 to your computer and use it in GitHub Desktop.
Save eduardobape/66983f605bc935c5010a0a5dd4eda787 to your computer and use it in GitHub Desktop.
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