数値
整数型
Kotlinは数値を扱ういくつかのビルドイン型を提供しています。 整数の数値に対しては、4つの型があり、それらはサイズと、その結果として値の範囲が異なります:
| 型 | サイズ (bits) | 最小値 | 最大値 |
|---|---|---|---|
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) |
変数に明示的に型をつけずに初期化する場合、コンパイラは自動的に格納に必要な十分なサイズを持つ中で一番小さな型を、しかしIntから始めて類推します。
もしIntの範囲を越えていなければ、型はIntになります。
もしIntを超えていたらLongになります。
Longの値を明示的に指示するためには、値の最後にLをつけます。
明示的に型を指定すると、コンパイラはその型の範囲に値が収まっているかをチェックするようになります。
val one = 1 // Int
val threeBillion = 3000000000 // Long
val oneLong = 1L // Long
val oneByte: Byte = 1
整数型の他に、Kotlinは符号なし整数型も提供しています。詳細は符号なし整数型を参照。
浮動小数点型
実数に関しては、KotlinはFloatとDoubleの浮動小数点を提供しています。
IEEE 754 standardの標準に準拠していて、
Float は IEEE 754 のsingle precision(単精度)に、Double は double precision(倍精度)に対応しています。
(訳注:日本語のリンクIEEE 754)
これらの型はサイズが異なり、つまり格納する領域の大きさが異なります。 これは対応出来る精度の違いとなります:
| 型 | サイズ (bits) | 仮数(Significant) bits | 指数(Exponent) bits | 10進数での桁数 |
|---|---|---|---|---|
Float |
32 | 24 | 8 | 6-7 |
Double |
64 | 53 | 11 | 15-16 |
DoubleとFloatは、小数部を持つ数字を使う事で初期化出来る。
整数部と小数部はピリオド(.)で区切られる。
小数を持つ数で初期化すると、コンパイラはDouble型だと推測する。
val pi = 3.14 // Double
// val one: Double = 1 // Error: 型が合わない
val oneDouble = 1.0 // Double
値を明示的にFloatとしたければ、接尾辞(suffix)にfかFを使う。
それらの接尾辞をつけて、しかも6〜7桁より大きい桁数の場合は丸められる。
val e = 2.7182818284 // Double
val eFloat = 2.7182818284f // Float, 実際の値は 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: 型が合わない
// printDouble(f) // Error: 型が合わない
}
数値の値を別の型に変換するには、明示的な変換を使用してください。
数値のリテラル定数
整数値のためのリテラル定数は、次の種類があります:
There are the following kinds of literal constants for integral values:
- 数値:
123 - Long型の数を表すには大文字の
Lを末尾につける:123L - 16進数:
0x0F - 2進数:
0b00001011
Kotlinでは8進数のリテラルはサポートされていません。
Kotlinは従来の浮動小数点数の表記法もサポートしています:
- デフォルトではdouble型:
123.5,123.5e10 - float型を表すには
forFでタグ付けする: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上での表現
Javaプラットフォームでは、JVMプリミティブ型、つまりintやdoubleとして数値が物理的に格納されています。
そうで無くなるのは、null許容型な数値の参照(例:Int?)やジェネリクスが関与している場合です。
そうしたケースでは数値はJavaのIntegerクラスやDoubleクラスなどにボクシングされています。
同じ数値のNullableなリファレンスは、別のオブジェクトを参照する場合がありえます:
aについてのすべてのnullableなリファレンスは、実際にはすべて同じオブジェクトを指します。
これはJVMがIntegerのうち-128から127の数値には特別な最適化を施すためです。
これはbには適用されない為、nullableリファレンスはそれぞれ違うオブジェクトを指します。
一方、==では同一と判定されます:
数値の明示的な変換
異なる表現であるため、小さな型は大きな型のサブタイプではありません。 もし仮にそうであったならば、次の種類の悩みを抱えたでしょう:
// 仮説のコードであり、実際はコンパイルできません:
val a: Int? = 1 // ボクシングされたInt型 (java.lang.Integer)
val b: Long? = a // 暗黙の変換がLong型 (java.lang.Long)へのボクシングを引き起こします
print(a == b) // 仰天!これはLong型のequals()チェックで他の部分がLong型になるのと同等に "false" を出力します
つまり、同一性だけでなくequalityでさえも何も言わずに失われたのです。
その結果、小さな型は、大きな型に暗黙的に変換される事はありません。これは明示的変換無しでByte型の値をInt型へ代入することができないことを意味します。
すべての数値型は、他の型への変換をサポートします:
toByte(): BytetoShort(): ShorttoInt(): InttoLong(): LongtoFloat(): FloattoDouble(): Double
多くの場合、明示的変換の必要はありません。 なぜなら型は文脈から推測され、算術演算が適切にオーバロードされていてそこで必要な変換がされるからです。例えば:
val l = 1L + 3 // Long + Int => Long
数値に対する演算
Kotlinは数値に対する標準的な算術計算は一通りサポートしています: +, -, *, /, % など。
それらは適切なクラスのメンバとして宣言されています:
カスタムなクラスでも、これらの演算子をオーバーロードする事が出来ます。 演算子のオーバーロードを参照してください。
整数の割り算
二つの整数型の間の割り算の結果は、必ず整数型になります。端数は切り捨てられます。
これはどの二つの整数型の間の割り算でも適用されます:
浮動小数点型の結果がほしければ、引数のどちらかを明示的に浮動小数点型に変換する必要があります:
ビット演算
Kotlinは、整数値に対する一通りのビット演算(bitwise operations)を提供します。
それらの演算は数値の内部表現レベルでビットに直接演算を行います。
ビット演算は中置形で呼ぶ事の出来る関数として表されます。
それらはIntとLongにしかありません:
val x = (1 shl 2) and 0x000FF000
これらはビット演算の全リストです:
shl(bits)– 符号付き左シフトshr(bits)– 符号付き右シフトushr(bits)– 符号無し右シフトand(bits)– ビット演算のANDor(bits)– ビット演算のORxor(bits)– ビット演算のXORinv()– 各ビットを反転
浮動小数点数の比較
このセクションで議論する浮動小数点数の演算は以下になります:
- Equalityチェック:
a == banda != b - 比較演算:
a < b,a > b,a <= b,a >= b - 範囲(range)作成と範囲チェック:
a..b,x in a..b,x !in a..b
オペランドaとbが静的にFloatかDouble、またはそのnullableバージョンと判定出来る場合(型が明示的に宣言されているか型推論で決まるかスマートキャストの結果決まる場合)、
数値に対する演算やそれに基づいて作られる範囲(range)は、IEEE 754 Standard for Floating-Point Arithmeticに従います。
しかしながら、ジェネリクスや全順序を与えるために、静的に型が浮動小数点数と決まらないケースではこれらの振る舞いは異なります。
例えば、Any、Comparable<...>、Collection<T>型など。
このケースでは、上記の演算はFloatとDoubleに定義されているequalsとcompareToを使います。
その結果:
NaNのequalは自身と一致するNaNはPOSITIVE_INFINITYを含むいかなる他の要素よりも大きい-0.0は0.0より小さい
以下に、静的に浮動小数点数と型付けされるオペランド(Double.NaN)と、
静的に型付けされないオペランド(listOf(T))による違いを示します: