[//]: # (title: Numbers)
[//]: # (description: Learn how to use numbers in Kotlin, including numeric types, literals, conversions, arithmetic operations, overflow, and JVM-specific behavior.)
The Kotlin number types represent:
* Integer values ([Byte](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-byte/),
[Short](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-short/),
[Int](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/),
and [Long](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-long/))
* Floating-point values ([Float](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-float/)
and [Double](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-double/))
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 `Int` for whole numbers.
* Use `Long` for whole numbers outside the `Int` range.
* Use `Double` for decimal numbers.
* Use `Float` when lower precision is acceptable or required.
* Use `Byte` and `Short` when an API or data format requires them.
> Kotlin also provides [](unsigned-integer-types.md) as a Beta feature.
>
{style="tip"}
## Integer types
Kotlin provides four integer types with different sizes and value ranges:
| Type | Size (bits) | Min value | Max value |
|----------|-------------|----------------------------------------------|------------------------------------------------|
| `Byte` | 8 | -128 | 127 |
| `Short` | 16 | -32768 | 32767 |
| `Int` | 32 | -2,147,483,648 (-231) | 2,147,483,647 (231 - 1) |
| `Long` | 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: `123`
* Hexadecimals: `0x0F`
* Binaries: `0b00001011`
> Kotlin does not support octal literals.
>
{style="note"}
To declare a numeric value, specify the type explicitly:
```kotlin
val one: Int = 1
// Use underscores to improve readability
val oneBillion: Long = 1_000_000_000
val hexBytes: Int = 0x7F_EC_DE_5E
val bytes: Int = 0b01010010_01101001_10010100_10010010
val oneByte: Byte = 1
val oneShort: Short = 1
```
You can also append the `L` suffix, to declare a `Long` value:
```kotlin
val oneLong = 1L
```
When you declare a numeric type explicitly, the compiler checks that the value
fits in the range of that type:
```kotlin
// Value fits in Byte
val oneByte: Byte = 1
// Error: the value does not fit in Byte
val tooBig: Byte = 128
```
When you do not specify a numeric type, Kotlin infers `Int` if the
value fits in the `Int` range. Otherwise, Kotlin infers `Long`:
```kotlin
val million = 1_000_000 // Int
val threeBillion = 3_000_000_000 // Long
```
If a value can be absent, use nullable types:
```kotlin
val maybeAbsent: Int? = null
```
## Floating-point types
For numbers with a fractional part, Kotlin provides `Float` and `Double`.
Floating-point types follow
the [IEEE 754 standard](https://en.wikipedia.org/wiki/IEEE_754).
`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 |
|----------|-------------|------------------|---------------|----------------|
| `Float` | 32 | 24 | 8 | 6-7 |
| `Double` | 64 | 53 | 11 | 15-16 |
### Declare floating-point values
To declare a floating-point literal, include a decimal point (`.`) or use exponent notation:
```kotlin
val pi = 3.14
val avogadro = 6.02214076e23
```
By default, Kotlin infers floating-point literals as `Double`.
To declare a `Float`, add the `f` or `F` suffix:
```kotlin
val pi = 3.14 // Double
val eFloat = 2.7182817f // Float
```
> Kotlin rounds a `Float` literal that contains more precision than `Float` can store.
>
{style="note"}
If a value can be absent, use nullable types:
```kotlin
val maybeAbsent: Double? = null
```
## Arithmetic operations
Kotlin supports the standard arithmetic operations on numbers: `+`, `-`, `*`, `/`, and `%`.
Use these operators to perform common calculations:
```kotlin
fun main() {
//sampleStart
println(1 + 2) // 3
println(2_500_000_000L - 1L) // 2499999999
println(3.14 * 2.71) // 8.5094
println(10.0 / 3) // 3.3333333333333335
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
The result type depends on the types of the operands. Learn more in [](#mixed-numeric-expressions).
> You can override these operators in custom number classes.
> For more information, see [Operator overloading](operator-overloading.md).
>
{style="tip"}
### Integer division
Division between integer values always returns an integer result. The compiler discards the fractional part:
```kotlin
fun main() {
//sampleStart
val intValue = 5 / 2
println(intValue) // 2
val longValue = 5L / 2
println(longValue) // 2
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
To return a floating-point result, make at least one operand a `Float` or `Double`:
```kotlin
fun main() {
//sampleStart
val a = 5 / 2.0
println(a) // 2.5
val b = 5 / 2.toDouble()
println(b) // 2.5
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
## 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:
```kotlin
fun main() {
//sampleStart
fun printDouble(x: Double) {
print(x)
}
val x = 1.0
val xInt = 1
val xFloat = 1.0f
val one: Double = 1 // Error: initializer type mismatch
printDouble(x) // OK
printDouble(xInt) // Error: argument type mismatch
printDouble(xFloat) // Error: argument type mismatch
//sampleEnd
}
```
{kotlin-runnable="true" validate="false"}
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`:
```kotlin
fun main() {
//sampleStart
val intValue: Int = 1
val doubleValue = intValue.toDouble()
println(doubleValue) // 1.0
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
When you convert a floating-point value to an integer type, the compiler discards the fractional part:
```kotlin
fun main() {
//sampleStart
val d: Double = 1.5
val l: Long = d.toLong()
println(l) // 1
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
### 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:
```kotlin
val intNumber: Int = 1
val longNumber: Long = 1000
val result = intNumber + longNumber // 1001, Long
```
If you try to assign the result to a smaller type, the compiler reports an error:
```kotlin
val intNumber: Int = 1
val longNumber: Long = 1000
val result: Int = intNumber + longNumber
// Error: Initializer type mismatch
```
### Integer literal types
During type inference, Kotlin treats unsuffixed integer literals as a special [Integer Literal Type (ILT)](https://kotlinlang.org/spec/type-system.html#integer-literal-types)
until the surrounding context determines a specific type:
```kotlin
//sampleStart
fun List.log() {
println(joinToString(" | ") { it::class.simpleName ?: "Unknown" })
}
fun main() {
listOf(1, 2).log()
// Int | Int
listOf(1L, 2L).log()
// Long | Long
// Compiler interprets 1 as an ILT and resolves it to Long
listOf(1, 2L).log()
// Long | Long
// .toInt() converts the literal to Int
listOf(1.toInt(), 2L).log()
// Int | Long
}
//sampleEnd
```
{kotlin-runnable="true"}
It's especially easy to miss with the `Int` and `Long` values because they have the same string representation
at runtime. To avoid this, specify the expected type or convert values explicitly:
```kotlin
//sampleStart
fun List.log() {
println(joinToString(" | ") { it::class.simpleName ?: "Unknown" })
}
fun main() {
val longValues: List = listOf(1, 2L)
longValues.log()
// Long | Long
val numberValues: List = listOf(1.toInt(), 2L)
numberValues.log()
// Int | Long
}
//sampleEnd
```
{kotlin-runnable="true"}
You can also use an explicit type to catch unintended type inference:
```kotlin
fun main() {
//sampleStart
val intValues: List = listOf(1, 2L)
// Error: initializer type mismatch
//sampleEnd
}
```
{kotlin-runnable="true" validate="false"}
> Learn more about [Integer literal types](https://kotlinlang.org/spec/type-system.html#integer-literal-types).
>
{style="tip"}
## 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:
```kotlin
fun main(){
//sampleStart
val intNumber: Int = 2147483647
// Max Int value is 2147483647
println(intNumber + 1) // -2147483648
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Here, the result wraps around because the value no longer fits in `Int`.
> The compiler does not automatically produce an error when integer overflow occurs.
>
{style="note"}
### Overflow in negation
Overflow can also occur during negation.
For example, you cannot represent the positive counterpart of `Int.MIN_VALUE` as an `Int`.
```kotlin
fun main(){
//sampleStart
val min = Int.MIN_VALUE
println(-min) // -2147483648
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
### Narrowing conversions
When you convert a value to a smaller integer type,
the result may not preserve the original numeric value:
```kotlin
fun main() {
//sampleStart
val large: Int = 130
val narrowed: Byte = large.toByte()
println(narrowed) // -126
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
However, since floating-point types follow the
[IEEE 754 Standard](https://en.wikipedia.org/wiki/IEEE_754), very large results can become `Infinity`:
```kotlin
fun main() {
//sampleStart
println(Double.MAX_VALUE * 2) // Infinity
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
## Bitwise operations
Kotlin provides _bitwise operations_ for `Int` and `Long`. These operations are represented by
a set of [infix functions](functions.md#infix-notation) and `inv()`.
```kotlin
fun main() {
//sampleStart
val x = 1
println(x shl 2) // 4
println(x and 0x000FF000) // 0
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Bitwise operations include:
* `shl()` – signed shift left
* `shr()` – signed shift right
* `ushr()` – unsigned shift right
* `and()` – bitwise AND
* `or()` – bitwise OR
* `xor()` – bitwise XOR
* `inv()` – 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](https://en.wikipedia.org/wiki/IEEE_754).
However, in generic use cases (such as `Any`, `Comparable<...>`, or `Collection`), 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:
* `NaN` is considered equal to itself
* `NaN` is considered greater than any other element including `POSITIVE_INFINITY`
* `-0.0` is considered less than `0.0`
The following example shows the difference between operands statically typed as floating-point numbers
and operands used through generic types:
```kotlin
//sampleStart
fun generalizedEquals(a: Any, b: Any): Boolean {
return a == b
}
fun main() {
// Operands statically typed as floating-point numbers
println(Double.NaN == Double.NaN) // false
println(0.0 == -0.0) // true
// Operands used through a non-floating-point static type
println(generalizedEquals(Double.NaN, Double.NaN)) // true
println(generalizedEquals(0.0, -0.0)) // false
}
//sampleEnd
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" id="kotlin-numbers-floating-comp"}
## 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](generics.md) or nullable numeric types like `Int?`, the value is boxed and
represented as an object.
The JVM applies a [memory optimization technique](https://docs.oracle.com/javase/specs/jls/se22/html/jls-5.html#jls-5.1.7)
to small numbers by caching their boxed representations. As a result,
boxed numbers with the same value can be [referentially equal](equality.md#referential-equality).
For example, the JVM caches boxed `Integer` values in the range `-128` to `127`. Therefore, the following
code returns `true`:
```kotlin
fun main() {
//sampleStart
val score: Int = 100
val savedScore: Int? = score
val displayedScore: Int? = score
println(savedScore === displayedScore) // true
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" validate="false"}
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](equality.md#structural-equality).
For this reason, use `==` to compare numeric values:
```kotlin
fun main() {
//sampleStart
val score: Int = 10000
val savedScore: Int? = score
val displayedScore: Int? = score
println(savedScore === displayedScore) // false
println(savedScore == displayedScore) // true
//sampleEnd
}
```
{kotlin-runnable="true" kotlin-min-compiler-version="1.3" validate="false"}