Числа
Целочисленные типы
Kotlin предоставляет набор встроенных типов, представляющих числа.
Для целых чисел существуют четыре типа с различными размерами и, следовательно, диапазонами значений:
Тип |
Размер (биты) |
Минимальное значение |
Максимальное значение |
|---|---|---|---|
|
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) |
Когда вы инициализируете переменную без явного указания типа, компилятор автоматически определяет тип с наименьшим диапазоном, достаточным для представления значения. Если оно не превышает диапазон Int, тип является Int. Если превышает, тип является Long. Чтобы явно указать значение Long, добавьте суффикс L к значению. Явное указание типа заставляет компилятор проверять, не превышает ли значение диапазон указанного типа.
val one = 1 // Int val threeBillion = 3000000000 // Long val oneLong = 1L // Long val oneByte: Byte = 1
Типы с плавающей точкой
Для вещественных чисел Kotlin предоставляет типы с плавающей точкой Float и Double, которые соответствуют стандарту IEEE 754. Float отражает IEEE 754 одинарную точность, а Double отражает двойную точность.
Эти типы отличаются по размеру и обеспечивают хранение чисел с плавающей точкой с различной точностью:
Тип |
Размер (биты) |
Значимые биты |
Биты экспоненты |
Десятичные цифры |
|---|---|---|---|---|
|
32 |
24 |
8 |
6-7 |
|
64 |
53 |
11 |
15-16 |
Вы можете инициализировать переменные Double и Float числами, имеющими дробную часть. Она отделена от целой части точкой (.) Для переменных, инициализированных дробными числами, компилятор определяет тип Double:
val pi = 3.14 // Double // val one: Double = 1 // Error: type mismatch val oneDouble = 1.0 // Double
Чтобы явно указать тип Float для значения, добавьте суффикс f или F. Если такое значение содержит более 6-7 десятичных цифр, оно будет округлено:
val e = 2.7182818284 // Double val eFloat = 2.7182818284f // Float, actual value is 2.7182817
В отличие от некоторых других языков, в Kotlin нет неявных расширяющих преобразований для чисел. Например, функцию с параметром Double можно вызывать только со значениями Double, но не со значениями Float, Int, или другими числовыми значениями:
fun main() {
fun printDouble(d: Double) { print(d) }
val i = 1
val d = 1.0
val f = 1.0f
printDouble(d)
// printDouble(i) // Error: Type mismatch
// printDouble(f) // Error: Type mismatch
}
Для преобразования числовых значений в разные типы используйте явные преобразования.
Литеральные константы для чисел
Существуют следующие виды литеральных констант для целочисленных значений:
-
Десятичные:
123Целые типа Long помечаются заглавной буквой
L:123L
Шестнадцатеричные:
0x0FДвоичные:
0b00001011
Kotlin также поддерживает стандартную запись для чисел с плавающей точкой:
По умолчанию Double:
123.5,123.5e10Float помечаются суффиксом
fилиF:123.5f
Вы можете использовать нижние подчеркивания, чтобы сделать числовые константы более читабельными:
val oneMillion = 1_000_000 val creditCardNumber = 1234_5678_9012_3456L val socialSecurityNumber = 999_99_9999L val hexBytes = 0xFF_EC_DE_5E val bytes = 0b11010010_01101001_10010100_10010010
Представление чисел в JVM
На платформе JVM числа хранятся как примитивные типы: int, double, и так далее. Исключение составляют случаи, когда вы создаёте ссылку на число с возможностью значения null, например, Int?, или используете дженерики. В этих случаях числа упаковываются в классы Java Integer, Double, и так далее.
Ссылки с возможностью значения null на одно и то же число могут ссылаться на разные объекты:
fun main() {
//sampleStart
val a: Int = 100
val boxedA: Int? = a
val anotherBoxedA: Int? = a
val b: Int = 10000
val boxedB: Int? = b
val anotherBoxedB: Int? = b
println(boxedA === anotherBoxedA) // true
println(boxedB === anotherBoxedB) // false
//sampleEnd
}
Все ссылки с возможностью значения null на a фактически являются одним и тем же объектом из-за оптимизации памяти, которую JVM применяет к Integer между -128 и 127. Она не применяется к ссылкам b, поэтому они являются разными объектами.
В то же время они всё ещё равны:
fun main() {
//sampleStart
val b: Int = 10000
println(b == b) // Prints 'true'
val boxedB: Int? = b
val anotherBoxedB: Int? = b
println(boxedB == anotherBoxedB) // Prints 'true'
//sampleEnd
}
Явные преобразования чисел
Из-за различного представления, типы меньшего размера не являются подтипами более крупных. Если бы они были, у нас возникли бы проблемы следующего типа:
// Hypothetical code, does not actually compile: val a: Int? = 1 // A boxed Int (java.lang.Integer) val b: Long? = a // Implicit conversion yields a boxed Long (java.lang.Long) print(b == a) // Surprise! This prints "false" as Long's equals() checks whether the other is Long as well
Таким образом, равенство было бы потеряно неявно, не говоря уже о тождестве.
Следовательно, типы меньшего размера не преобразуются неявно в типы большего размера. Это означает, что присваивание значения типа Byte переменной типа Int требует явного преобразования:
fun main() {
//sampleStart
val b: Byte = 1 // OK, literals are checked statically
// val i: Int = b // ERROR
val i1: Int = b.toInt()
//sampleEnd
}
Все числовые типы поддерживают преобразования в другие типы:
toByte(): BytetoShort(): ShorttoInt(): InttoLong(): LongtoFloat(): FloattoDouble(): Double
Во многих случаях явные преобразования не нужны, так как тип определяется из контекста, а арифметические операции перегружены для соответствующих преобразований, например:
val l = 1L + 3 // Long + Int => Long
Операции над числами
Kotlin поддерживает стандартный набор арифметических операций над числами: +, -, *, /, %. Они объявлены как члены соответствующих классов:
fun main() {
//sampleStart
println(1 + 2)
println(2_500_000_000L - 1L)
println(3.14 * 2.71)
println(10.0 / 3)
//sampleEnd
}
Вы также можете переопределить эти операторы для пользовательских классов. Подробнее см. Перегрузку операторов.
Деление целых чисел
Деление целых чисел всегда возвращает целое число. Любая дробная часть отбрасывается.
fun main() {
//sampleStart
val x = 5 / 2
//println(x == 2.5) // ERROR: Operator '==' cannot be applied to 'Int' and 'Double'
println(x == 2)
//sampleEnd
}
Это верно для деления любых двух целых типов:
fun main() {
//sampleStart
val x = 5L / 2
println(x == 2L)
//sampleEnd
}
Чтобы получить число с плавающей точкой, явно преобразуйте один из аргументов в тип с плавающей точкой:
fun main() {
//sampleStart
val x = 5 / 2.toDouble()
println(x == 2.5)
//sampleEnd
}
Битовые операции
Kotlin предоставляет набор битовых операций над целыми числами. Они работают на битовом уровне непосредственно с битами представления чисел. Битовые операции представлены функциями, которые могут вызываться в инфиксной форме. Они могут применяться только к Int и Long:
val x = (1 shl 2) and 0x000FF000
Вот полный список битовых операций:
shl(bits)— сдвиг влево со знакомshr(bits)— сдвиг вправо со знакомushr(bits)— сдвиг вправо без знакаand(bits)— побитовое Иor(bits)— побитовое ИЛИxor(bits)— побитовое Исключающее ИЛИinv()— инверсия битов
Сравнение чисел с плавающей точкой
Операции над числами с плавающей точкой, обсуждаемые в этом разделе:
Проверка на равенство:
a == bиa != bОператоры сравнения:
a < b,a > b,a <= b,a >= bСоздание и проверка диапазонов:
a..b,x in a..b,x !in a..b
Когда операнды a и b статически известны как Float или Double или их nullable аналоги (тип объявлен, выведен или является результатом интеллектуального преобразования типа), операции над числами и диапазон, который они образуют, следуют стандарту IEEE 754 для арифметики с плавающей точкой.
Однако, чтобы поддержать общие случаи использования и обеспечить полное упорядочение, когда операнды не являются статически типизированными как числа с плавающей точкой (например, Any, Comparable<...>, параметр типа), операции используют реализации equals и compareTo для Float и Double, которые отличаются от стандарта, так что:
NaNсчитается равным самому себеNaNсчитается больше любого другого элемента, включаяPOSITIVE_INFINITY-0.0считается меньше0.0
© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/numbers.html