Kotlin `toInt()` Two's Complement - kotlin

I believe FFFFFFFF is -1 because of Two's Complement.
I tried to convert Hex String into Integer, but I got the error.
Here is the code I have tried.
code
// Extension functions
val Int.asByteArray get() =
byteArrayOf(
(this shr 24).toByte(),
(this shr 16).toByte(),
(this shr 8).toByte(),
this.toByte())
val Int.asHex get() = this.asByteArray.asHexUpper
// Main Code
fun main()
{
println((-1).asHex)
println("FFFFFFFF".toInt(16))
}
Result
FFFFFFFF
Exception in thread "main" java.lang.NumberFormatException: For input string: "FFFFFFFF"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Integer.parseInt(Integer.java:652)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
Is this intended? or Is this error?
If this is intended, then what should I do?

Your code presumably can't parse 4 bytes (32 bit) to a signed integer, since this only contains 31 bits as one bit is reserved for the sign.
A solution would be to parse it into an unsigned integer (as Some random IT boy stated) and then convert the (16bit-)UInt to a (16bit-)Int:
fun main()
{
val u = "FFFFFFFF".toUInt(16) //16 as it is base 16
println(u) //prints "4294967295"
val v = u.toInt()
println(v) //prints "-1"
}
Use with caution as this will not work when your data is not of length 32: You can not parse FFFF and expect it to be -1 as it would be parsed to 0000FFFF which is equal to 65535.
For data lengths of 1, 2 or 8 bytes, look into the data types Byte, Short or Long and their respective Functions:
val u = "FFFFFFFF".toULong(16)
println(u) //prints 4294967295
val v = u.toLong()
println(v) //still prints 4294967295

It's -1 because the first bit of the 4 byte memory block decides the sign of the number. In this case since it's all 1's then it's a negative number. Then the value of this memory block is the Two's complement because we're dealing with a signed integer
The problem you're facing is not Kotlin specific: checkout this question from StackOverflow
Java has also trouble parsing such string to an Integer, but a Long has no trouble; because it has 4 more bytes to spare, and in fact, if you'd write the value literal 0xFFFFFFFF Kotlin grabs it as if it's a Long:
A quick fix for these could be to use the unsigned counterpart of the int UInt
"FFFFFFFF".toUInt(16) // 4294967295
Or just use a Long
In https://kotlinlang.org/

Related

Kotlin String to ULong

I'm using Kotlin on Linux (kotlinc-jvm 1.7.21)
I would like to store a large number in a variable. So I found ULong to store 64 bits numbers.
My number in binary is : 1111100001111100001111100001111110001111110001111110001111110001. This is 64 bits long, so just under the limit of a ULong variable.
However, when I try to convert it from String to ULong,
var myLargeNumber = "1111100001111100001111100001111110001111110001111110001111110001".toULong()
I have the error :
Exception in thread "main" java.lang.NumberFormatException: Invalid number format: '1111100001111100001111100001111110001111110001111110001111110001'
myLargeNumber.toULong() will try to interpret the number in base 10. 1111100001111100001111100001111110001111110001111110001111110001 is a lot larger than the maximum ULong value of 18446744073709551615, so toULong() fails
To interpret the number as a binary number you can instead specify the radix:
fun main() {
val myLargeNumber = "1111100001111100001111100001111110001111110001111110001111110001"
.toULong(radix = 2) // treat the string as a base 2 number
println(myLargeNumber)
// output: 17905254523795399665
}

Input out of range for Int datatype, not passing a testcase

I am trying to solve the following question on LeetCode; Write a function that takes an unsigned integer and returns the number of '1' bits it has. Constraints: The input must be a binary string of length 32.
I have written the following code for that which works fine for inputs 00000000000000000000000000001011 and 00000000000000000000000010000000 (provided internally by the website) but give output 0 for input 11111111111111111111111111111101 and in my local compiler for the last input it says "out of range"
class Solution {
// you need treat n as an unsigned value
fun hammingWeight(n:Int):Int {
var num = n
var setCountBit = 0
while (num > 0) {
setCountBit++
num= num and num-1
}
return setCountBit
}
}
To correctly convert binary string to Int and avoid "out of range error", you need to do the following (I believe LeetCode does the same under the hood):
fun binaryStringToInt(s: String): Int = s.toUInt(radix = 2).toInt()
"11111111111111111111111111111101" is equivalent to 4294967293. This is greater than Int.MAX_VALUE, so it will be represented as negative number after .toInt() convertion (-3 in this case).
Actually, this problem could be solved with one-liner in Kotlin 1.4:
fun hammingWeight(n: Int): Int = n.countOneBits()
But LeetCode uses Kotlin 1.3.10, so you need to adjust your solution to handle negative Ints as well.
Please change the type of your input variable from Int to a type like Double .At the moment The given value is bigger than the maximum value that a type Int number can store.

kotlin type mismatch with shl operator

I am developing a small communications protocol over bluetooth for an arduino to transfer data to Android. Part of the protocol sends a header that contains a line count. I have successfully read the MSB and LSB of the count and must now re-assemble that from the Int to a Short value. My declarations follow:
var iLineCountMSB: Int = 0
var iLineCountLSB: Int = 0
var sLineCountMSB: Short = 0
var sLineCount: Short = 0
I have already read the MSB and LSB from the bluetooth socket. Please note that the values are in Int, not Byte. My attempt to re-assemble the two Ints to a Short is as follows:
sLineCount = iLineCountMSB.toShort() shl 8 + iLineCountLSB.toShort()
I also copied the MSB Int value to a Short (sLineCountMSB):
sLineCountMSB = iLineCountMSB.toShort()
sLineCount = sLineCountMSB shl 8
I continue to get the same error:
-- results in:: Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public inline infix fun BigInteger.shl(n: Int): BigInteger defined in kotlin
The Kotlin documentation defines the function as:
infix fun shl(bitCount: Int): Long
Am I wrong? Does this specifiy that 'Long' is the returned type? The only 'shl' that I seem to get to compile successfully is Int = Int shl 8.

Why single char and "single char String" not equal when converted to long (.toLong())

I wanted to sum the digits of Long variable and add it to the variable it self, I came with the next working code:
private fun Long.sumDigits(): Long {
var n = this
this.toString().forEach { n += it.toString().toLong() }
return n
}
Usage: assert(48.toLong() == 42.toLong().sumDigits())
I had to use it.toString() in order to get it work, so I came with the next test and I don't get it's results:
#Test
fun toLongEquality() {
println("'4' as Long = " + '4'.toLong())
println("\"4\" as Long = " + "4".toLong())
println("\"42\" as Long = " + "42".toLong())
assert('4'.toString().toLong() == 4.toLong())
}
Output:
'4' as Long = 52
"4" as Long = 4
"42" as Long = 42
Is it a good practice to use char.toString().toLong() or there is a better way to convert char to Long?
Does "4" represented by chars? Why it is not equal to it char representation?
From the documentation:
class Char : Comparable (source) Represents a 16-bit Unicode
character. On the JVM, non-nullable values of this type are
represented as values of the primitive type char.
fun toLong(): Long
Returns the value of this character as a Long.
When you use '4' as Long you actually get the Unicode (ASCII) code of the char '4'
As mTak says, Char represents a Unicode value. If you are using Kotlin on the JVM, you can define your function as follows:
private fun Long.sumDigits() = this.toString().map(Character::getNumericValue).sum().toLong()
There's no reason to return Long rather than Int, but I've kept it the same as in your question.
Non-JVM versions of Kotlin don't have the Character class; use map {it - '0'} instead.

Declaring Byte in Kotlin does compile-time error 'The integer literal does not conform to the expected type Byte'

As seen another question in 0xFF0000FF An integer literal does not conform to the expected type kotlin.Int
I declaring value 0xFF as Byte
val b:Byte = 0xFF
receiving The integer literal does not conform to the expected type Byte compile error
Since I have clue about kotlin.Byte is signed byte
How to declaring Byte in Kotlin with 0x00 - 0xFF unsigned byte just like .net Byte b = 0xFF ?
.
.
If you want instant compiler for testing and answer:
rextester , try.kotlinlang.org
Kotlin doesn't automatically convert between number types.
If you do val b:Byte = 0xFF.toByte() then it compiles and results in a byte with value -1.
If you want to hold the unsigned byte value then you need to store it as a Char, but you will need to convert it to another type to print it as a number:
val b = 0xFF.toChar()
println(b.toInt())
Kotlin now supports unsigned integer types:
val b: UByte = 255u
val c: UByte = 0xFFu