Kotlin String to ULong - kotlin

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
}

Related

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 `toInt()` Two's Complement

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/

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

How to convert String to Long in Kotlin?

So, due to lack of methods like Long.valueOf(String s) I am stuck.
How to convert String to Long in Kotlin?
1. string.toLong()
Parses the string as a [Long] number and returns the result.
#throws NumberFormatException if the string is not a valid
representation of a number.
2. string.toLongOrNull()
Parses the string as a [Long] number and returns the result or null
if the string is not a valid representation of a number.
3. string.toLong(10)
Parses the string as a [Long] number and returns the result.
#throws NumberFormatException if the string is not a valid
representation of a number.
#throws IllegalArgumentException when
[radix] is not a valid radix for string to number conversion.
public inline fun String.toLong(radix: Int): Long = java.lang.Long.parseLong(this, checkRadix(radix))
4. string.toLongOrNull(10)
Parses the string as a [Long] number and returns the result or null
if the string is not a valid representation of a number.
#throws IllegalArgumentException when [radix] is not a valid radix for string
to number conversion.
public fun String.toLongOrNull(radix: Int): Long? {...}
5. java.lang.Long.valueOf(string)
public static Long valueOf(String s) throws NumberFormatException
String has a corresponding extension method:
"10".toLong()
Extension methods are available for Strings to parse them into other primitive types. Examples below:
"true".toBoolean()
"10.0".toFloat()
"10.0".toDouble()
"10".toByte()
"10".toShort()
"10".toInt()
"10".toLong()
Note: Answers mentioning jet.String are outdated. Here is current Kotlin (1.0):
Any String in Kotlin already has an extension function you can call toLong(). Nothing special is needed, just use it.
All extension functions for String are documented. You can find others for standard lib in the api reference
Actually, 90% of the time you also need to check the 'long' is valid, so you need:
"10".toLongOrNull()
There is an 'orNull' equivalent for each 'toLong' of the basic types, and these allow for managing invalid cases with keeping with the Kotlin? idiom.
It's interesting. Code like this:
val num = java.lang.Long.valueOf("2");
println(num);
println(num is kotlin.Long);
makes this output:
2
true
I guess, Kotlin makes conversion from java.lang.Long and long primitive to kotlin.Long automatically in this case. So, it's solution, but I would be happy to see tool without java.lang package usage.
In Kotlin, to convert a String to Long (that represents a 64-bit signed integer) is simple.
You can use any of the following examples:
val number1: Long = "789".toLong()
println(number1) // 789
val number2: Long? = "404".toLongOrNull()
println("number = $number2") // number = 404
val number3: Long? = "Error404".toLongOrNull()
println("number = $number3") // number = null
val number4: Long? = "111".toLongOrNull(2) // binary
println("numberWithRadix(2) = $number4") // numberWithRadix(2) = 7
With toLongOrNull() method, you can use let { } scope function after ?. safe call operator.
Such a logic is good for executing a code block only with non-null values.
fun convertToLong(that: String) {
that.toLongOrNull()?.let {
println("Long value is $it")
}
}
convertToLong("123") // Long value is 123
One good old Java possibility what's not mentioned in the answers is java.lang.Long.decode(String).
Decimal Strings:
Kotlin's String.toLong() is equivalent to Java's Long.parseLong(String):
Parses the string argument as a signed decimal long. ... The
resulting long value is returned, exactly as if the argument and the
radix 10 were given as arguments to the parseLong(java.lang.String, int) method.
Non-decimal Strings:
Kotlin's String.toLong(radix: Int) is equivalent to Java's eLong.parseLong(String, int):
Parses the string argument as a signed long in the radix specified by
the second argument. The characters in the string must all be digits of the specified radix ...
And here comes java.lang.Long.decode(String) into the picture:
Decodes a String into a Long. Accepts decimal, hexadecimal, and octal
numbers given by the following grammar: DecodableString:
(Sign) DecimalNumeral | (Sign) 0x HexDigits | (Sign) 0X HexDigits | (Sign) # HexDigits | (Sign) 0 OctalDigits
Sign: - | +
That means that decode can parse Strings like "0x412", where other methods will result in a NumberFormatException.
val kotlin_toLong010 = "010".toLong() // 10 as parsed as decimal
val kotlin_toLong10 = "10".toLong() // 10 as parsed as decimal
val java_parseLong010 = java.lang.Long.parseLong("010") // 10 as parsed as decimal
val java_parseLong10 = java.lang.Long.parseLong("10") // 10 as parsed as decimal
val kotlin_toLong010Radix = "010".toLong(8) // 8 as "octal" parsing is forced
val kotlin_toLong10Radix = "10".toLong(8) // 8 as "octal" parsing is forced
val java_parseLong010Radix = java.lang.Long.parseLong("010", 8) // 8 as "octal" parsing is forced
val java_parseLong10Radix = java.lang.Long.parseLong("10", 8) // 8 as "octal" parsing is forced
val java_decode010 = java.lang.Long.decode("010") // 8 as 0 means "octal"
val java_decode10 = java.lang.Long.decode("10") // 10 as parsed as decimal
If you don't want to handle NumberFormatException while parsing
var someLongValue=string.toLongOrNull() ?: 0
Actually, there are several ways:
Given:
var numberString : String = "numberString"
// number is the Long value of numberString (if any)
var defaultValue : Long = defaultValue
Then we have:
+—————————————————————————————————————————————+——————————+———————————————————————+
| numberString is a valid number ? | true | false |
+—————————————————————————————————————————————+——————————+———————————————————————+
| numberString.toLong() | number | NumberFormatException |
+—————————————————————————————————————————————+——————————+———————————————————————+
| numberString.toLongOrNull() | number | null |
+—————————————————————————————————————————————+——————————+———————————————————————+
| numberString.toLongOrNull() ?: defaultValue | number | defaultValue |
+—————————————————————————————————————————————+——————————+———————————————————————+
string.toLong()
where string is your variable.