KotlinのDouble型
はじめに
本記事ではKotlinのDouble
型の仕様に関して確認したことをまとめます.
等価演算子
import kotlin.Double.Companion.NaN fun main() { println(NaN == NaN) // false println(NaN != NaN) // true println(NaN as Any == NaN) // true println(NaN as Any != NaN) // false println(0.0 == -0.0) // true println(0.0 as Any == -0.0) // false }
Kotlinの等価演算子は両辺が静的にDouble
型であるときはIEEE 754に従います.
そのため,NaN == NaN
はfalse
となります.
また,NaN != NaN
はtrue
となります.
しかし,NaN as Any == NaN
は左辺がAny
型であるため,equals
メソッドによってtrue
となります.
また,NaN as Any != NaN
は左辺がAny
型であるため,false
となります.
同様に,0.0 == -0.0
はIEEE 754に従ってtrue
となりますが,0.0 as Any == -0.0
はequals
メソッドによってfalse
となります.
関係演算子
import kotlin.Double.Companion.NEGATIVE_INFINITY as nInf import kotlin.Double.Companion.POSITIVE_INFINITY as pInf import kotlin.Double.Companion.NaN fun main() { println(NaN < NaN) // false println(NaN > NaN) // false println(NaN < pInf) // false println(NaN > pInf) // false println(NaN < nInf) // false println(NaN > nInf) // false println(NaN <= NaN) // false println(NaN as Comparable<Double> <= NaN) // true println(-0.0 < 0.0) // false println(-0.0 as Comparable<Double> < 0.0) // true }
Kotlinの関係演算子は両辺が静的にDouble
型であるときはIEEE 754に従います.
そのため,右辺または左辺がNaN
であるときは,関係演算子の結果はfalse
となります.
また,-0.0 < 0.0
はfalse
となります.
しかし,NaN as Comparable<Double> <= NaN
は左辺がComparable<Double>
型であるため,compareTo
メソッドを用いて判定され,結果はtrue
となります.
同様に,-0.0 as Comparable<Double> < 0.0
は左辺がComparable<Double>
型であるため,compareTo
メソッドを用いて判定され,結果はtrue
となります.
四則演算
import kotlin.Double.Companion.NEGATIVE_INFINITY as nInf import kotlin.Double.Companion.POSITIVE_INFINITY as pInf fun main() { // plus println(pInf + 1.0) // Infinity println(nInf + 1.0) // -Infinity println(pInf + pInf) // Infinity println(pInf + nInf) // NaN println(nInf + nInf) // -Infinity // times println(pInf * pInf) // Infinity println(pInf * 2.0) // Infinity println(pInf * 0.0) // NaN println(pInf * -0.0) // NaN println(pInf * -2.0) // -Infinity println(pInf * nInf) // -Infinity println(nInf * pInf) // -Infinity println(nInf * 2.0) // -Infinity println(nInf * 0.0) // NaN println(nInf * -0.0) // NaN println(nInf * -2.0) // Infinity println(nInf * nInf) // Infinity // minus println(pInf - 1.0) // Infinity println(nInf - 1.0) // -Infinity println(pInf - pInf) // NaN println(pInf - nInf) // Infinity println(nInf - pInf) // -Infinity println(nInf - nInf) // NaN // div println(pInf / pInf) // NaN println(pInf / 2.0) // Infinity println(pInf / 0.0) // Infinity println(pInf / -0.0) // -Infinity println(pInf / -2.0) // -Infinity println(pInf / nInf) // NaN println(pInf / pInf) // NaN println(2.0 / pInf) // 0.0 println(0.0 / pInf) // 0.0 println(-0.0 / pInf) // -0.0 println(-2.0 / pInf) // -0.0 println(nInf / pInf) // NaN println(pInf / nInf) // NaN println(2.0 / nInf) // -0.0 println(0.0 / nInf) // -0.0 println(-0.0 / nInf) // 0.0 println(-2.0 / nInf) // 0.0 println(nInf / nInf) // NaN }
KotlinのDouble
型の演算でオーバーフローが発生する場合は演算の結果はInfinity
となります.
アンダーフローが発生する場合は演算の結果は-Infinity
となります.
また,Int
型の除算と異なり,Double
型の除算では割る数が0.0
であっても例外が発生しません.
pow
import kotlin.math.pow import kotlin.Double.Companion.NEGATIVE_INFINITY as nInf import kotlin.Double.Companion.POSITIVE_INFINITY as pInf import kotlin.Double.Companion.NaN fun main() { // a^0.0 == 1.0 println(0.0.pow(0.0)) // 1.0 println(NaN.pow(0.0)) // 1.0 println(pInf.pow(0.0)) // 1.0 println(nInf.pow(0.0)) // 1.0 // a^1.0 == a println(0.0.pow(1.0)) // 0.0 println(NaN.pow(1.0)) // NaN println(pInf.pow(1.0)) // Infinity println(nInf.pow(1.0)) // -Infinity // a^Infinity println(pInf.pow(pInf)) // Infinity println(2.0.pow(pInf)) // Infinity println(1.0.pow(pInf)) // NaN println(0.5.pow(pInf)) // 0.0 println(0.0.pow(pInf)) // 0.0 println((-0.0).pow(pInf)) // 0.0 println((-0.5).pow(pInf)) // 0.0 println((-1.0).pow(pInf)) // NaN println((-2.0).pow(pInf)) // Infinity println(nInf.pow(pInf)) // Infinity // a^-Infinity println(pInf.pow(nInf)) // 0.0 println(2.0.pow(nInf)) // 0.0 println(1.0.pow(nInf)) // NaN println(0.5.pow(nInf)) // Infinity println(0.0.pow(nInf)) // Infinity println((-0.0).pow(nInf)) // Infinity println((-0.5).pow(nInf)) // Infinity println((-1.0).pow(nInf)) // NaN println((-2.0).pow(nInf)) // 0.0 println(nInf.pow(nInf)) // 0.0 // a^b (a < 0.0) println((-2.0).pow(2.0)) // 4.0 println((-2.0).pow(2.5)) // NaN println((-2.0).pow(3.0)) // -8.0 }
NaN.pow(0.0)
はNaN
ではなく1.0
,1.0.pow(pInf)
および1.0.pow(nInf)
は1.0
ではなくNaN
,(-2.0).pow(pInf)
,nInf.pow(pInf)
および(-0.5).pow(nInf)
はNaN
ではなくInfinity
,pInf.pow(nInf)
はNaN
ではなく0.0
となりました.
これらはJavaのMath.pow
の規定に合致するものですが私の直感に反するものだったため気をつけなければいけないと感じました.
log
import kotlin.math.log import kotlin.Double.Companion.NEGATIVE_INFINITY as nInf import kotlin.Double.Companion.POSITIVE_INFINITY as pInf fun main() { println(log(pInf, pInf)) // NaN println(log(2.0, pInf)) // 0.0 println(log(1.0, pInf)) // 0.0 println(log(0.5, pInf)) // -0.0 println(log(0.0, pInf)) // NaN println(log(-0.0, pInf)) // NaN println(log(pInf, 2.0)) // Infinity println(log(2.0, 2.0)) // 1.0 println(log(1.0, 2.0)) // 0.0 println(log(0.5, 2.0)) // -1.0 println(log(0.0, 2.0)) // -Infinity println(log(-0.0, 2.0)) // -Infinity println(log(pInf, 0.5)) // -Infinity println(log(2.0, 0.5)) // -1.0 println(log(1.0, 0.5)) // -0.0 println(log(0.5, 0.5)) // 1.0 println(log(0.0, 0.5)) // Infinity println(log(-0.0, 0.5)) // Infinity }
Kotlinのlog
に関して,特に気になる結果はありませんでした.