How to split a Long into two Ints in Kotlin? - kotlin

How can I split a Long (64bit) into two Integer (32bit) in Kotlin?
I've tried something like this but it doesn't seem to be doing it:
val id = Integer.MAX_VALUE.toLong() + 2000
val a = id.toInt()
val b = (id shr 32).toInt()

Everything is working fine. Note that Integer.MAX_VALUE is 0x7FFFFFFF, when you add 2000, it becomes 0x800007CF, which is still within 32-bit, but overflow to the negative number range when interpreted as 32-bit signed integer. Therefore a is a negative Int and b is 0

Related

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

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.

Hex and Int bitwise operation confict

Why in Kotlin bitwise operation is not possible with 4-byte hex and Int?
At the same time, there is no problem in Java
As far as I know, in JVM int takes 4 bytes.
// Kotlin
val num = 0
val n = 0xff000000 or num // <-- 'num' ERROR
// Java
int num = 0;
int n = 0xff000000 | num; // <-- 'num' OK
0xFF000000 is a Long, not an Int. It's outside the Int range since it is using 32 bits to represent a positive number, but Int only uses 31 bits for the number, and one bit for the sign. Any six-digit hexadecimal number where the first digit is greater than 7 requires 32 bits to represent the number, so it is interpreted as a Long.
Kotlin doesn't do implicit number conversions like Java because they can easily lead to obscure bugs. You have to manually convert it to an Int.
val num = 0
val n = 0xff000000.toInt() or num

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

Integer multiplication overflow

I have problem with multiplying two integers in Objective C. When I multiply 500 with 20000000 and save in a long variable and print it the result is 1410065408.
int x = 500;
long myLongValue = x * 20000000;
NSLog(#" %lu",myLongValue);
I think the problem is about overflowing integers, but I couldn't find real reason. I try to find the real result 10000000000, using multiplication of these integers. Is it possible?
You have an overflow here : an unsigned int is coded using 32bits, so the max value will be 2^32-1, 4294967295. An int is coded using 31 bits (1 bit is for the sign), and the max will be 2147483647.
As you can see here, the 33h bit is used to represent your number, so you cannot represent it with an int. Guess which number you'll get if you set this bit to 0 ? ;)
SOLUTION EDITED : Even if you assign the result to a long value, the result is first stored into an int, so you should cast your values to long before performing the multiplication in objC. Also, as rmaddy noticed in the comments, using a long variable doesn't work in 32bit architecture since longis coded using 4bytes. You should use long long type instead, or use explicit types such as int32_t and int64_t.
int x = 500;
long long myLongValue = (long long)x * 20000000;
NSLog(#" %llu",myLongValue); // logs correctly 10000000000
You can also declare your x directly as a long long variable.
FYI : swift is not as tolerant as objC, and your example code will crash because of the 'out-of range' bit :
let a:Int32 = 20000000
let b:Int32 = 500
let result = a*b // CRASH
let result2 = Int64(a)*Int64(b) // OK

How to combine 2 different integers to create a single float (or a double)

I'm Cesare from Italy (please excuse my english), this is my first question posted on StackOverflow and I'm pretty new to Objective-C... I hope I won't make a mess on my first try.
I would like to "combine" two integers that I already have to create a new float (or a double).
By "combine", I mean that I'd like to have the first int before the point and the second int after the point, I'm not trying to convert from int to float. Maybe an example could explain better what I'm trying to do:
First int: 7
Second int: 92
The float I'm trying to get: 7.92
I looked for a previous question like mine but I haven't found anything, maybe because what I'm trying to do is pretty dumb (I have a UIPickerView with 2 components, each containing hundreds of integers, and I'm trying to create a float or double variable that has the selection of the first component before the point and the selection of the second component after the point).
Thanks in advance for your help,
Cesare
Just think about what the definition and/or the purpose of the decimal point is. It separates the part of the number which is less than one from the part greater than or equal to one.
So, keep dividing the part after the decimal point until it's less than 1:
int firstPart = 7;
int secondPart = 92; // or whatever
float f = secondPart;
while (f >= 1) {
f /= 10;
}
f += firstPart;
I know this is later, but came across a similar situation. Maybe this is more efficient.
Take the second number, 92 and divide it by 100. That gives you .92. Add that to the first number. That can give you 7.92. However, since you're adding integers that you want converted to a float, you'll need to cast the numbers when adding them. Like this:
int firstPart = 7;
int secondPart = 92;
float afterDecimalPlace = (float)secondPart/100.0;
float numberAsFloat = (float)firstPart + afterDecimalPlace;
essentially that is:
92/100 = .92
7 + .92 = 7.92