As I mentioned here, Kotlin has different data types you can use to store information. In this post, I will focus on the ones used to hold numbers, since there are different ways to store both whole numbers and decimals depending on how much data you need the variable to hold.
The different numeric types are defined basically based on the number of bits allocated in the memory, so how much space they take, and that is directly related to the minimum and maximum values each type can hold.
These are the most commonly used numeric types ordered by size:
|Byte (whole)||8||127||– 128|
|Short (whole)||16||32,767||– 32,768|
|Int (whole)||32||2,147,483,647||– 2,147,483,648|
📌 Short and Byte are not frequently used to represent common numbers. Usually, you use them in special cases or to support interoperability with other languages. For most purposes, whole numbers are represented either by an Int or a Long if larger numbers are needed.
An integer (Int) is a whole number. It does not have a decimal point. You can use integers to count things and perform arithmetic operations using the +, -, /, *, % operators.
2 + 4 * 5 // result is 22 10 / 5 // result is 2 9 % 2 // result is 1 (modulus or remainder) 7 / 2 // result is 3 because integers don't have a decimal
Please note that Kotlin’s multiplicative operators (*, /, and %) take precedence over additive operators (+, -), just like in regular mathematics.
You can use either a Float or a Double if you need to store or return decimals. Doubles can store twice as many bits as a Float number (hence the name Double) and can handle precision better.
These numbers in Kotlin can also hold special values for infinity, negative infinity, and NaN – not a number. These values are usually returned when performing an illegal or undefined operation, like a division by zero (which returns infinity / negative infinity) or the square
root of a negative number (which returns NaN).
Now, if you try dividing 7.0 by 3.0 you will get the actual result, not the approximated whole number you get if you use an Int.
7.0 / 3.0 // result is 2.3333333333333335
That said, 7.0 can be either a Float or a Double, right? But if you run this code on REPL you will see that Kotlin defaults it to Double:
If you want to make sure you are using a Float you can add an f to the end of the numbers and REPL will evaluate it as a Float:
If you use the suffix f after the number you can drop the decimal (if it’s .0 and won’t interfere in the calculation) and if that’s the case, the f only needs to be added to one of the numbers:
That said, because of the way Floats are structured and translated into Machine Language, they can’t always precisely represent numbers. They are an approximation in most cases. So, to avoid this, it’s preferable to default to Doubles when using decimal numbers.
Another option, if you are targetting the JVM, is to use BigDecimal, which is a much more powerful data type that holds numbers (decimals) and avoids precision errors as well but at the expense of increased complexity compared to the basic numeric types and, consequently, requires more resources.
📌 Worth noting: Starting on Kotlin version 1.5 (as of this moment the current version is 1.6.10) it started supporting signed and unsigned numbers. Unsigned numbers are very similar to the numbers types I mentioned above, only they cannot hold negative values. They are represented with the letter u in front of them and they hold the same number of bits. So, since they can’t hold negative values their minimum value is 0 (zero) and their maximum value is twice the value of their signed counterparts. Also, the decimal numeric types, Float and Double don’t have an unsigned version.
So, for example, the Byte has 8 bits and it can go from 127 to -128, while its unsigned counterpart is called UByte, it also has 8 bits but it goes from 0 (zero) to 255.
One thought on “Numbers in Kotlin”