Kotlin - Numbers (숫자)

Language/Kotlin 2018.07.10 00:17 posted by TechNote.kr


Kotlin은 numbers를 다음과 같은 built-in type을 가지고 있다. 



Type

 Bit width

 Range

Byte

8

-128 ~ 127

Short

16

-32768 ~ 32767

Int

32

-2147483648 ~ 2147483647

Long

64

-9223372036854775808 ~ 9223372036854775807

Float

32

 -

Double

64

 -



일부 언어(e.g. C언어)에서는 chararacter 형이 숫자로 표현되기도 하지만 Kotlin에서 문자는 numbers가 아니다. 



1) Byte


bit width : 8

range : -128 ~ 127 (8-bit signed two's complement integer)


일반적으로 memory 사용을 줄이기 위해 [-128, 127] 사이의 integer data를 표현하기 위한 목적으로 Int type 대신 사용된다.


[Byte 일반적 사용]

fun main(args: Array<string>) {
    val value: Byte = 100
    println("$value")
}

[결과]

100 


[범위를 벗어난 Byte 사용]

fun main(args: Array<string>) {
    val value: Byte = 200
    println("$value")
}

[결과]

Error:(2, 23) Kotlin: The integer literal does not conform to the expected type Byte 



2) Short


bit width : 16

range : -32768 ~ 32767 (16-bit signed two's complement integer)


Byte와 마찬가지로 memory 사용을 줄이기 위해 [-32768, 32767] 사이의 integer data를 표현하기 위한 목적으로 Int type 대신 사용된다.


[Short 일반적 사용]

fun main(args: Array<string>) {
    val value: Short = 200
    println("$value")
}

[결과]

200 


[범위를 벗어난 Short 사용]

fun main(args: Array<string>) {
    val value: Short = 58273
    println("$value")
}

[결과]

Error:(2, 24) Kotlin: The integer literal does not conform to the expected type Short 



3) Int


bit width : 32

range : -2147483648 ~ 2147483647 (32-bit signed two's complement integer)


type을 명시적으로 쓰지 않으면 Int type 으로 설정된다. 


[Int 일반적 사용]

fun main(args: Array<string>) {
    val value: Int = 58273
    println("$value")
}

[결과]

58273 


[범위를 벗어난 Int 사용]

fun main(args: Array<string>) {
    val value: Int = 1947212432847
    println("$value")
}

[결과]

Error:(2, 22) Kotlin: The integer literal does not conform to the expected type Int 



4) Long


bit width : 64

range : -9223372036854775808 ~ 9223372036854775807 (64-bit signed two's complement integer)


[Long 일반적 사용]

fun main(args: Array<string>) {
    val value: Long = 1947212432847
    println("$value")
}

[결과]

1947212432847 


만약 명시적으로 Long type 변수를 사용하려면 대문자 L을 아래와 같이 숫자에 붙여주면 된다.


val value = 100L 



5) Double


Double type : double-precision 64 bit floating point


double-precision은 8 bytes (64 bits)로 표현되는데 이 64 bits는 sign, exponent, fraction bit로 구성되어 있다. 

sign(S) : 0번째 비트

exponent(E) : 1~11번째 비트

fraction(F) : 나머지 비트


S EEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
0 1        11 12                                                63


fun main(args: Array<string>) {
    val value = 1024.1
    println("$value")
}

 1024.1



6) Float


Float type : single-precision 32 bit floating point


single-precision은 4 bytes (32 bits)로 표현되는데 이 32 bits는 sign, exponent, fraction bit로 구성되어 있고, 이를 표현하기 위해 literal constant에 F를 붙여주어야 한다. 


sign(S) : 0번째 비트

exponent(E) : 1~8번째 비트

fraction(F) : 나머지 비트


S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
0 1      8 9                    31


fun main(args: Array<string>) {
    val value = 1024.1F
    println("$value")
}

 1024.1


F가 없는 Double type의 literal은 Float type에 할당하지 못한다. 


fun main(args: Array<string>) {
    val value = 1024.1F
    value = 1024.2
    println("$value")
}

Error:(3, 13) Kotlin: The floating-point literal does not conform to the expected type Float 



Literal Constants


Literal Constants라는 말을 정확히 우리말로 표현하기가 쉽지 않은 것 같다. Literal 을 사전에서 찾아보면 '글자 그대로의' 혹은 한글로 '리터럴'이라고 나온다. 

wikipedia 참고하여 이해하자면 코드상 고정된 값이라고 보면 될 것 같다.


Kotlin에서는 다음과 같이 literal constant를 표현한다.


Long, Int, Short, Byte 의 경우

Decimals (10진수) : 123 (Long 형은 L을 숫자 뒤에 붙여 123L로 표현한다.)

Hexadecimals (16진수) : 0x0F

Binaries (2진수) : 0b00001011

8진수는 지원하지 않는다. 


Double, Float 의 경우

Double : 123.5, 123.5e10 (부동 소수점을 사용하면 기본적으로 Double이 표현된다.)

Float : 123.5f (Float 형은 f나 F를 붙여 표현한다.)


Kotlin 1.1 부터는 Underscore를 이용하여 numeric literal을 표현가능하다.


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



Explicit Conversions (명시적 type 변환)


type 별로 서로다른 표기법을 가지고 있기 때문에 표현할 수 있는 숫자의 범위가 작은 type이 큰 type의 subtype이 되지는 않는다. 


실제 compile 되지는 않는 코드이지만 아래 코드를 예를 들어 보면 다음과 같다. 


val a: Int? = 1
val b: Long? = a
print(b == a)


만약 실제 compile이 되는 코드 였다면 3번째 line에서 false를 출력했을 것이다. 즉, Int의 1과 Long의 1은 다르다. 암시적(implicitly)으로 type 변환은 이루어 지지 않는다.


위의 코드는 2번째 line에서 compile error가 발생할 것이다. Int형의 1을 Long형의 변수에 할당하려고 했기 때문이다. Compile이 발생하지 않게 하기 위해서는 2번째 줄의 코드를 아래와 같이 변환이 필요하다.


var b: Long? = a.toLong()


모든 number type은 다음 function을 통해 변환이 가능하다.


toByte(): Byte

toShort(): Short

toInt(): Int

toLong(): Long

toFloat(): Float

toDouble(): Double

toChar(): Char



Operations



Kotlin은 Java와 마찬가지로 기본적인 산술 연산 뿐만 아니라 operator overloading을 통해 원하는 연산을 하게 할 수 있다. Kotlin에서 bitwise operation은 특별히 표현되는 연산자는 없지만, infix form이라 불리는 function을 통해 수행된다. 

(단, Int와 Long type에서만 사용 가능하다.)


val x = (1 shl 2) and 0x000FF000

shl(bits) – signed shift left (Java's <<)

shr(bits) – signed shift right (Java's >>)

ushr(bits) – unsigned shift right (Java's >>>)

and(bits) – bitwise and

or(bits) – bitwise or

xor(bits) – bitwise xor

inv() – bitwise inversion



Smart Casts


정확히 어떤 type의 Numbers가 사용될지 모를 때는 Number type을 사용할 수 있다. 

Number type는 integer나 floating-point 값을 모두 담을 수 있다. 

Runtime 도중에도 smart cast를 통해 자유롭게 type 변환이 가능하다. 


fun main(args: Array<string>) {
    var value: Number = 12.2
    println("$value")

    value = 18
    // Int smart cast from Number
    println("$value")

    value = 620L
    // Long smart cast from Number
    println("$value")
}

12.2

18

620