Kotlin. How to convert string to Int without loosing precision? - kotlin

I'm trying to convert String to Int. The String can contain number as Int or as Double. But I need to convert string to Int anyway.
Here is my code:
val str = "999.13"
val number = str.toDoubleOrNull()?.roundToInt() ?: 0 // number will be 999
It works but there is one problem. If the source string will contain a very large number, for example 99999999999, then I get an incorrect number. After casting the string to a double, I lose precision.
What is the best way to perform such a manipulation without loss of precision? I would like to refrain from using BigDecimal, BigInteger etc.
Perhaps there is a more elegant solution for kotlin, please help me.

There's no way for Double and Long to hold bigger values than their largest possible values, so of course you will lose precision. That's why BigDecimal/BigInteger exist. They are the only ways to handle numbers that are bigger than the largest values Double and Long can handle, unless you want to handle parsing of the String yourself (note, you are parsing with toDoubleOrNull(), not casting).
I'm not sure why you'd want to avoid BigDecimal, but you could split the number at the decimal place, use toIntOrNull() or toLongOrNull() on the first part of the String and use toFloatOrNull() on the second part so you can round it to either 0 or 1 and add that to the first part to do the rounding:
val result = if ("." !in input)
input.toIntOrNull()
else {
val (firstPart, secondPart) = input.split(".")
val integerPart = firstPart.toIntOrNull()
integerPart?.let { it + (".$secondPart".toFloatOrNull()?.roundToInt() ?: 0) }
}
It would be a bit easier to use BigDecimal.
val result = runCatching {
BigDecimal(input).setScale(0, RoundingMode.HALF_UP).toInt()
}.getOrNull()
Both of the above would be simpler if you already know your input is valid.

Related

How would i separate an answer in Kotlin do print 2 different types

Hi this is my first ever program I'm tryin to write in android studio/Kotlin and I'm not sure how to proceed.
so in my program i have a few math tasks to do and it does it fine but what I need to do now is separate part of the answer then covert it then print out both parts
for example if my answer was 1.5232 i would like to convert the decimal part of the answer to a string that matches a range if its in it. the ranges I have are in the .0000 area so I would like to limit the decimal range too.
so final result would look like this
1 (whatever my string in range is)
I hope I included enough info thank you in advance.
The first part of the task is to split the number into the integer and fractional components:
val input = 1.5232
val integer = input.toInt() // rounds DOWN to nearest smaller Int
val fractional = input % 1.0 // The remainder when dividing by 1.0 is the fraction
The strategy I would use to round to the nearest fractional value given a certain precision is to multiply by that precision, and round to the nearest integer. That would give you the numerator, and the precision would be the denominator:
val denominator = 8 // fractional precision
val numerator = (fractional * denominator).roundToInt() // rounds up or down to nearest Int
Then to put it together, you can use a string template:
val result = "$integer $numerator/$denominator"
println(result)
Simplifying the fraction would be another task if you need that. You can find various algorithms for finding greatest common divisor of two numbers. Use one of those and divide the numerator and denominator by that value.

In Kotlin how can i make a function to count TAX or VAT?

In Kotlin how can i make a function to count the TAX or VAT of a price i had inputted earlier?
For example: i input a number (467) and from that number i want have the sum with the tax. Here in Greece we have 24% tax or VAT.
fun main(args: Array<String>) {
var input = readLine()
println(tax(0.24))
}
fun tax(x: Double): Double {
return 0.24 * x
}
in the end i want to have the price i inputed in the start for example 467 * 24% <-- TAX or VAT amount.
I am trying to figura that out but i cant.. :/
I may be misunderstanding the question, because it seems pretty basic…
The code in the question reads a number from the user into the variable input, but does nothing with it.  So I suspect what you want to do is println(tax(input)).
However, if you try that, you'll get a compile error:
Type mismatch.
Required: Double
Found: String?
input is a String (or null if end-of-file), but your tax() function needs a Double number.  So what you have to do is to convert the String to a number.  The easiest way is by calling the String's toDouble() method.
If you do that, you'll get another compiler error, because you're not handling the possibility that input could be null (and you can't call toDouble() on a null).  So you have to check for that first, e.g.:
if (input != null)
println(tax(input.toDouble())
I think that gives what you want.
But there are many improvements worth making, e.g.:
You probably don't want to be using a floating-point binary type like Double, as that can't store decimal fractions exactly.  (It rounds to the nearest decimal when displaying, which often masks the problem, but it comes back to bite you in many subtle ways.)  Instead, you could use the BigDecimal type which doesn't have that problem.
The tax rate should be a constant, so you don't have to repeat it anywhere else.
You could include a prompt to the user, and then extra information in the output by using a string template (as #Sid suggests).  In that case, it's best to store the price to avoid having to convert it twice.
Since you're not modifying input after creating it, it's safer to make it an immutable val rather than a var.
You can use the shorter expression form of the tax() function.
With all those changes, it might look something like this:
val TAX_RATE = BigDecimal("0.24")
fun main(args: Array<String>) {
println("Enter the price:")
val input = readLine()
if (input != null) {
val price = input.toBigDecimal()
val taxPercentage = TAX_RATE.scaleByPowerOfTen(2)
println("€$price * tax # $taxPercentage% = €${tax(price)}")
}
}
fun tax(x: BigDecimal) = TAX_RATE * x
I'm assuming the price is in euros; in a more sophisticated program the currency would probably be passed/input with the price.  And in practice, tax calculations are usually far more complex (e.g. handling items which have different rates, zero rates, or are exempt from tax, and tax may not be payable anyway depending who the buyer is)…
(By the way, ‘tax’ is not an abbreviation, so isn't usually capitalised.)
You can do something like this:
fun readLn() = readLine()!!
fun readNumAndCalcGreekTax() {
println("Enter a number")
val userInput = readLn().toInt()
val userInputPlusTax = userInput * 1.24
println("For $userInput plus %24 tax: Total: $userInputPlusTax")
}
readNumAndCalcGreekTax()
And the output will be
Enter a number
460
For 460 plus %24 tax: Total: 570.4

Why the value of int variable changes after converting it to string index to int?

fun main(){
val num=348597
println(num.toString()[0].toInt())
}
I should be getting 3 as the output but I'm getting 51 instead.
Does anyone know why, or what I can do instead to get 3 as the result?
num.toString() gives you "348597". Taking [0] from it returns the first Char '3' which is a 16-bit unicode character value. Calling toInt() just converts the character value to an integer. In unicode the codepoints < 128 are the same as in ASCII and 51 is the value for the character '3'.
To get the character as a string representing "3", change toInt() to toString().
Yo, I found the easy way how to solve this problem. I was getting 51 because I was converting char to int directly and it was returning ASCII value or shit instead. So here is the code:
fun main(){
val num=348597
//use Character.getNumericValue() instead
println(Character.getNumericValue(num.toString()[0])) }
I found the answer here.

kotlin rem operator doesn't give me correct answer

I use remainder inside my code with kotlin in android project but with this value I don't get the correct answer.
variable is :
val vv = 1529.71
val ratio = 0.01
val remainder = vv.rem(ratio)
it's must be zero but remainder value is :
4.5363018896793506E-15
I don't understand why this happened.
The answer is because vv isn't actually 1529.71 but the closest possible Double, the exact value is 1529.7100000000000363797880709171295166015625 (the easiest way to see it is println(java.math.BigDecimal(vv))). If you want to represent decimal numbers exactly, use BigDecimal and pass the fraction as a string:
val vv = BigDecimal("1529.71")
val ratio = BigDecimal("0.01")
val remainder = vv.rem(ratio)
Read more about floating point here: https://floating-point-gui.de/
In my case, i had to get only the exact digits of two numbers after the decimal point.
I achieved it by doing this:
val input = 30.47f
val remainder = (input * 100).toInt() - (input.toInt() * 100)
// remainder = 47 exactly, and not 469999999...
Hope this would be helpful for someone.

How to divide two Int a get a BigDecimal in Kotlin?

I want to divide two Integers and get a BigDecimal back in Kotlin.
E.g. 3/6 = 0.500000.
I've tried some solutions, like:
val num = BigDecimal(3.div(6))
println("%.6f".format(num))
// The result is: 0.000000
but none of them solve my problem.
3 and 6 are both Int, and dividing one Int by another gives an Int: that's why you get back 0. To get a non-integer value you need to get the result of the division to be a non-integer value. One way to do this is convert the Int to something else before dividing it, e.g.:
val num = 3.toDouble() / 6
num will now be a Double with a value of 0.5, which you can format as a string as you wish.
You might have better luck with:
val num = 3.toBigDecimal().divide(6.toBigDecimal())
println(num)
// prints 0.5
You have to convert both numbers to BigDecimal for the method to work. This will show the exact quotient, or throw an exception if the exact quotient cannot be represented (ie a non-terminating decimal).
You can set the scale and rounding mode as follows:
val num = 3.toBigDecimal().divide(6.toBigDecimal(), 4, RoundingMode.HALF_UP)
println(num)
// prints 0.5000
Link to reference article
Dividing Int by Int will give Int result only. To get float result , you need to convert one of the number to float.
You can use toFloat() function also.
var result = Int.toFloat() / Int