Numbers
The Kotlin number types represent:
Use number types to store and process numeric data, for example, in arithmetic, counters, measurements, and other calculations.
Choose a number type
In most cases, you can refer to the following rules to determine the correct number type for your task:
Use
Intfor whole numbers.Use
Longfor whole numbers outside theIntrange.Use
Doublefor decimal numbers.Use
Floatwhen lower precision is acceptable or required.Use
ByteandShortwhen an API or data format requires them.
Integer types
Kotlin provides four integer types with different sizes and value ranges:
Type | Size (bits) | Min value | Max value |
|---|---|---|---|
| 8 | -128 | 127 |
| 16 | -32768 | 32767 |
| 32 | -2,147,483,648 (-231) | 2,147,483,647 (231 - 1) |
| 64 | -9,223,372,036,854,775,808 (-263) | 9,223,372,036,854,775,807 (263 - 1) |
Declare integer values
Kotlin supports the following literal forms for integer values:
Decimals:
123Hexadecimals:
0x0FBinaries:
0b00001011
To declare a numeric value, specify the type explicitly:
You can also append the L suffix, to declare a Long value:
When you declare a numeric type explicitly, the compiler checks that the value fits in the range of that type:
When you do not specify a numeric type, Kotlin infers Int if the value fits in the Int range. Otherwise, Kotlin infers Long:
If a value can be absent, use nullable types:
Floating-point types
For numbers with a fractional part, Kotlin provides Float and Double.
Floating-point types follow the IEEE 754 standard. Float reflects the single precision. Double reflects the double precision.
Floating-point types differ in size and precision:
Type | Size (bits) | Significant bits | Exponent bits | Decimal digits |
|---|---|---|---|---|
| 32 | 24 | 8 | 6-7 |
| 64 | 53 | 11 | 15-16 |
Declare floating-point values
To declare a floating-point literal, include a decimal point (.) or use exponent notation:
By default, Kotlin infers floating-point literals as Double. To declare a Float, add the f or F suffix:
If a value can be absent, use nullable types:
Arithmetic operations
Kotlin supports the standard arithmetic operations on numbers: +, -, *, /, and %.
Use these operators to perform common calculations:
The result type depends on the types of the operands. Learn more in Mixed numeric expressions.
Integer division
Division between integer values always returns an integer result. The compiler discards the fractional part:
To return a floating-point result, make at least one operand a Float or Double:
Type conversion
Numeric types are not subtypes of one another. Kotlin requires explicit conversions to avoid silent data loss and unexpected behavior.
For example, a function that expects Double cannot accept an Int or a Float value without conversion:
All number types support conversions to other number types. To convert a number to another type, use an explicit conversion function:
toByte()toShort()toInt()toLong()toFloat()toDouble()
For example, the following code converts an Int value to Double:
When you convert a floating-point value to an integer type, the compiler discards the fractional part:
Mixed numeric expressions
Kotlin does not support implicit conversion for assignments or function arguments. However, you can combine different numeric types in arithmetic expressions. In such cases, Kotlin determines a result type based on the operand types, and arithmetic operators handle the conversion automatically:
If you try to assign the result to a smaller type, the compiler reports an error:
Data overflow
Numeric types can represent only values within their defined ranges.
If the result of an operation falls outside that range, overflow occurs. If you convert a value to a smaller numeric type, the converted value may not preserve the original numeric value.
This behavior can affect the result of your code even when the compiler accepts it.
Overflow in operations
Each integer type can store only values within its defined range. When the result of an arithmetic operation exceeds that range, data overflow occurs:
Here, the result wraps around because the value no longer fits in Int.
Overflow in negation
Overflow can also occur during negation. For example, you cannot represent the positive counterpart of Int.MIN_VALUE as an Int.
Narrowing conversions
When you convert a value to a smaller integer type, the result may not preserve the original numeric value:
However, since floating-point types follow the IEEE 754 Standard, very large results can become Infinity:
Bitwise operations
Kotlin provides bitwise operations for Int and Long. These operations are represented by a set of infix functions and inv().
Bitwise operations include:
shl()– signed shift leftshr()– signed shift rightushr()– unsigned shift rightand()– bitwise ANDor()– bitwise ORxor()– bitwise XORinv()– bitwise inversion
Floating-point number comparison
In Kotlin, floating-point comparison depends on the static type of the operands.
When the operands are statically known to be Float or Double, operations on the numbers and the range that they form follow the IEEE 754 Standard for Floating-Point Arithmetic.
However, in generic use cases (such as Any, Comparable<...>, or Collection<T>), behavior differs for operands that are not statically typed as floating-point numbers. In these cases, Kotlin uses the equals() and compareTo() implementations for Float and Double.
As a result:
NaNis considered equal to itselfNaNis considered greater than any other element includingPOSITIVE_INFINITY-0.0is considered less than0.0
The following example shows the difference between operands statically typed as floating-point numbers and operands used through generic types:
Boxing and caching numbers on the JVM
On the JVM, non-nullable numeric values are usually stored using primitive types, such as int, long, or double. However, when you use generic types or nullable numeric types like Int?, the value is boxed and represented as an object.
The JVM applies a memory optimization technique to small numbers by caching their boxed representations. As a result, boxed numbers with the same value can be referentially equal.
For example, the JVM caches boxed Integer values in the range -128 to 127. Therefore, the following code returns true:
For values outside the cached range, boxed values are separate objects. In that case, they are not referentially equal, even if their values are structurally equal. For this reason, use == to compare numeric values: