Spec-Zone.ru › Kotlin 2

Числа

Числовые типы Kotlin представляют:

  • Целочисленные значения (Byte, Short, Int и Long)

  • Числа с плавающей точкой (Float и Double)

Используйте числовые типы для хранения и обработки числовых данных, например, в арифметических операциях, счетчиках, измерениях и других вычислениях.

Выбор числового типа

В большинстве случаев для выбора подходящего для вашей задачи числового типа можно руководствоваться следующими правилами:

  • Используйте Int для целых чисел.

  • Используйте Long для целых чисел, выходящих за пределы диапазона Int.

  • Используйте Double для десятичных чисел.

  • Используйте Float, если допустима или требуется меньшая точность.

  • Используйте Byte и Short, если этого требует API или формат данных.

В Kotlin также есть беззнаковые целочисленные типы, доступные в качестве бета-функции.

Целочисленные типы

В Kotlin есть четыре целочисленных типа с разными размерами и диапазонами значений:

Тип

Размер (в битах)

Минимальное значение

Максимальное значение

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)

Объявление целочисленных значений

Kotlin поддерживает следующие формы записи целочисленных литералов:

  • Десятичные: 123

  • Шестнадцатеричные: 0x0F

  • Двоичные: 0b00001011

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

Чтобы объявить значение типа Long, можно также добавить суффикс L:

val oneLong = 1L

Если числовой тип указан явно, компилятор проверяет, что значение входит в диапазон этого типа:

// Value fits in Byte
val oneByte: Byte = 1

// Error: the value does not fit in Byte
val tooBig: Byte = 128

Если числовой тип не указан, Kotlin выводит тип Int, если значение входит в диапазон Int. В противном случае Kotlin выводит тип Long:

val million = 1_000_000 // Int
val threeBillion = 3_000_000_000 // Long

Если значение может отсутствовать, используйте nullable-типы:

val maybeAbsent: Int? = null

Типы с плавающей точкой

Для чисел с дробной частью в Kotlin предусмотрены типы Float и Double.

Типы с плавающей точкой соответствуют стандарту IEEE 754. Float обеспечивает одинарную точность. Double обеспечивает двойную точность.

Типы с плавающей точкой различаются размером и точностью:

Тип

Размер (в битах)

Значащие биты

Биты экспоненты

Десятичные цифры

Float

32

24

8

6-7

Double

64

53

11

15-16

Объявление значений с плавающей точкой

Чтобы объявить литерал с плавающей точкой, добавьте десятичную точку (.) или используйте экспоненциальную запись:

val pi = 3.14
val avogadro = 6.02214076e23

По умолчанию Kotlin выводит для литералов с плавающей точкой тип Double. Чтобы объявить значение типа Float, добавьте суффикс f или F:

val pi = 3.14 // Double
val eFloat = 2.7182817f // Float

Kotlin округляет литерал типа Float, если его точность превышает ту, которую может сохранить Float.

Если значение может отсутствовать, используйте nullable-типы:

val maybeAbsent: Double? = null

Арифметические операции

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
}

Тип результата зависит от типов операндов. Подробнее см. в разделе Смешанные числовые выражения.

Эти операторы можно переопределить в пользовательских числовых классах. Подробнее см. в разделе Перегрузка операторов.

Целочисленное деление

При делении целочисленных значений результат всегда является целым числом. Компилятор отбрасывает дробную часть:

fun main() {
//sampleStart
    val intValue = 5 / 2
    println(intValue) // 2
    
    val longValue = 5L / 2
    println(longValue) // 2
//sampleEnd
}

Чтобы получить результат с плавающей точкой, задайте хотя бы один операнд как Float или Double:

fun main() {
//sampleStart
    val a = 5 / 2.0
    println(a) // 2.5
    
    val b = 5 / 2.toDouble()
    println(b) // 2.5
//sampleEnd
}

Преобразование типов

Числовые типы не являются подтипами друг друга. Чтобы избежать незаметной потери данных и неожиданного поведения, Kotlin требует явного преобразования типов.

Например, функция, ожидающая значение типа Double, не может принимать значение типа Int или Float без преобразования:

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
}

Все числовые типы поддерживают преобразование в другие числовые типы. Чтобы преобразовать число в другой тип, используйте явную функцию преобразования:

  • toByte()

  • toShort()

  • toInt()

  • toLong()

  • toFloat()

  • toDouble()

Например, следующий код преобразует значение типа Int в Double:

fun main() {
//sampleStart
    val intValue: Int = 1
    val doubleValue = intValue.toDouble()
    
    println(doubleValue) // 1.0
//sampleEnd
}

При преобразовании значения с плавающей точкой в целочисленный тип компилятор отбрасывает дробную часть:

fun main() {
//sampleStart
    val d: Double = 1.5
    val l: Long = d.toLong()
    
    println(l) // 1
//sampleEnd    
}

Смешанные числовые выражения

Kotlin не поддерживает неявное преобразование типов при присваивании или передаче аргументов функции. Однако в арифметических выражениях можно сочетать разные числовые типы. В таких случаях Kotlin определяет тип результата на основе типов операндов, а арифметические операторы автоматически выполняют преобразование:

val intNumber: Int = 1
val longNumber: Long = 1000
val result = intNumber + longNumber // 1001, Long

Если попытаться присвоить результат переменной меньшего типа, компилятор сообщит об ошибке:

val intNumber: Int = 1
val longNumber: Long = 1000
val result: Int = intNumber + longNumber 
// Error: Initializer type mismatch

Типы целочисленных литералов

При выводе типа Kotlin рассматривает целочисленные литералы без суффикса как специальный тип целочисленного литерала (ILT), пока окружающий контекст не определит конкретный тип:

//sampleStart
fun List<Any>.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

Эту особенность особенно легко не заметить со значениями Int и Long, поскольку во время выполнения они имеют одинаковое строковое представление. Чтобы этого избежать, укажите ожидаемый тип или преобразуйте значения явно:

//sampleStart
fun List<Any>.log() {
    println(joinToString(" | ") { it::class.simpleName ?: "Unknown" })
}

fun main() {
    val longValues: List<Long> = listOf(1, 2L)
    longValues.log()
    // Long | Long

    val numberValues: List<Number> = listOf(1.toInt(), 2L)
    numberValues.log()
    // Int | Long
}
//sampleEnd

Явный тип также можно использовать, чтобы обнаружить непреднамеренный вывод типа:

fun main() {
//sampleStart
    val intValues: List<Int> = listOf(1, 2L)
    // Error: initializer type mismatch
//sampleEnd
}

Подробнее см. в разделе Типы целочисленных литералов.

Переполнение данных

Числовые типы могут представлять только значения в пределах определенных для них диапазонов.

Если результат операции выходит за эти пределы, происходит переполнение. При преобразовании значения в числовой тип меньшего размера преобразованное значение может отличаться от исходного.

Такое поведение может повлиять на результат выполнения кода, даже если компилятор его принимает.

Переполнение при выполнении операций

Каждый целочисленный тип может хранить только значения в пределах заданного диапазона. Если результат арифметической операции выходит за эти пределы, происходит переполнение данных:

fun main(){
//sampleStart
    val intNumber: Int = 2147483647
    // Max Int value is 2147483647
    println(intNumber + 1) // -2147483648
//sampleEnd    
}

Здесь происходит циклический переход к началу диапазона, поскольку значение не помещается в Int.

Компилятор не сообщает об ошибке автоматически при переполнении целого числа.

Переполнение при отрицании

Переполнение также может произойти при отрицании. Например, положительное значение, противоположное Int.MIN_VALUE, нельзя представить типом Int.

fun main(){
//sampleStart
    val min = Int.MIN_VALUE
    println(-min) // -2147483648
//sampleEnd    
}

Преобразования с сужением диапазона

При преобразовании значения в целочисленный тип меньшего размера результат может отличаться от исходного значения:

fun main() {
//sampleStart
    val large: Int = 130
    val narrowed: Byte = large.toByte()

    println(narrowed) // -126
//sampleEnd
}

Однако, поскольку типы с плавающей точкой соответствуют стандарту IEEE 754, очень большие результаты могут стать Infinity:

fun main() {
//sampleStart
    println(Double.MAX_VALUE * 2) // Infinity
//sampleEnd    
}

Побитовые операции

В Kotlin доступны побитовые операции для Int и Long. Эти операции представлены набором инфиксных функций и inv().

fun main() {
//sampleStart
    val x = 1
    
    println(x shl 2) // 4
    println(x and 0x000FF000) // 0
//sampleEnd
}

К побитовым операциям относятся:

  • shl() — знаковый сдвиг влево

  • shr() — знаковый сдвиг вправо

  • ushr() — беззнаковый сдвиг вправо

  • and() — побитовое И

  • or() — побитовое ИЛИ

  • xor() — побитовое исключающее ИЛИ

  • inv() — побитовая инверсия

Сравнение чисел с плавающей точкой

В Kotlin способ сравнения чисел с плавающей точкой зависит от статического типа операндов.

Если статически известно, что операнды имеют тип Float или Double, операции над числами и образуемый ими диапазон соответствуют стандарту IEEE 754 для арифметики с плавающей точкой.

Однако в обобщенных сценариях (например, при использовании Any, Comparable<...> или Collection<T>) поведение операндов, статический тип которых не является типом с плавающей точкой, отличается. В таких случаях Kotlin использует реализации equals() и compareTo() для Float и Double.

В результате:

  • NaN считается равным самому себе

  • NaN считается больше любого другого элемента, включая POSITIVE_INFINITY

  • -0.0 считается меньше 0.0

В следующем примере показано различие между операндами со статическим типом числа с плавающей точкой и операндами, используемыми через обобщенные типы:

//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  

Упаковка и кэширование чисел в JVM

В JVM значения числовых типов, допускающих значение null, обычно хранятся с использованием примитивных типов, таких как int, long или double. Однако при использовании обобщенных типов или числовых nullable-типов, например Int?, значение упаковывается и представляется в виде объекта.

JVM применяет к небольшим числам технику оптимизации памяти, кэшируя их упакованные представления. В результате упакованные числа с одинаковыми значениями могут быть ссылочно равны.

Например, JVM кэширует упакованные значения Integer в диапазоне от -128 до 127. Поэтому следующий код возвращает true:

fun main() {
//sampleStart
    val score: Int = 100
    val savedScore: Int? = score
    val displayedScore: Int? = score
    
    println(savedScore === displayedScore) // true
//sampleEnd
}

Для значений за пределами кэшируемого диапазона упакованные значения являются отдельными объектами. В этом случае они не будут ссылочно равны, даже если их значения структурно равны. Поэтому для сравнения числовых значений используйте ==:

fun main() {
//sampleStart
    val score: Int = 10000
    val savedScore: Int? = score
    val displayedScore: Int? = score

    println(savedScore === displayedScore) // false
    println(savedScore == displayedScore) // true
//sampleEnd
}
18 июня 2026 г.
Обзор типовБеззнаковые целочисленные типы

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/numbers.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API