浮動小数点数の数値の種類
| 種類 | Java | Scala |
|---|---|---|
| 正の無限大 | Double.POSITIVE_INFINITY |
Double.NegativeInfinity |
| 正の数 | 例 1.0 |
例 1.0 |
| 正のゼロ | 0.0 |
0.0 |
| 負のゼロ | -0.0 |
-0.0 |
| 負の数 | 例 -1.0 |
例 -1.0 |
| 負の無限大 | Double.NEGATIVE_INFINITY |
Double.PositiveInfinity |
| NaN | Double.NaN |
Double.NaN |
ゼロが正負の2種類あるのとNaNがあるために数値の大小比較がややこしいです。
2つのゼロ
0.0と-0.0はどちらもゼロです。
-0.0は 0.0 / -1.0 などの計算結果として現れます。
比較演算子ではJavaでもScalaでも2つのゼロは同じ値として振る舞います。
0.0 == -0.0 // true 0.0 > -0.0 // false 0.0 >= -0.0 // false 0.0 != -0.0 // false
JavaのDouble.compareメソッドでは0.0と-0.0は違う値として振る舞います。
Double.compare(0.0, -0.0) // 1 Double.compare(-0.0, 0.0) // -1
ScalaのOrderingのcompareメソッドでも同様です。
Ordering.Double.IeeeOrdering.compare(0.0, -0.0) // 1 Ordering.Double.IeeeOrdering.compare(-0.0, 0.0) // -1 Ordering.Double.TotalOrdering.compare(0.0, -0.0) // 1 Ordering.Double.TotalOrdering.compare(-0.0, 0.0) // -1
NaN
NaNは非数(not-a-number)というものです。 0.0 / 0.0 などの計算結果として現れます。
!=以外の比較演算子ではJavaでもScalaでもNaNが含まれるとfalseを返します。NaN同士の==も常にfalseです。!=は常にtrueを返します。NaN同士の != もtrueです。
Double.NaN > Double.NaN // false Double.NaN == Double.NaN // false Double.NaN >= Double.NaN // false 0.0 > Double.NaN // false 0.0 < Double.NaN // false 0.0 != Double.NaN // true Double.NaN != Double.NaN // true
JavaのDouble.compareメソッドではNaNは正の無限大よりも大きな値として振る舞います。
Double.compare(Double.NaN, 0.0) // 1 Double.compare(Double.NaN, Double.POSITIVE_INFINITY) // 1 Double.compare(0.0, Double.NaN) // -1 Double.compare(Double.POSITIVE_INFINITY, Double.NaN) // -1
ScalaのOrderingのcompareメソッドでも同様です。
Ordering.Double.IeeeOrdering.compare(Double.NaN, 0.0) // 1 Ordering.Double.IeeeOrdering.compare(Double.NaN, Double.PositiveInfinity) // 1 Ordering.Double.IeeeOrdering.compare(0.0, Double.NaN) // -1 Ordering.Double.IeeeOrdering.compare(Double.PositiveInfinity, Double.NaN) // -1 Ordering.Double.TotalOrdering.compare(Double.NaN, 0.0) // 1 Ordering.Double.TotalOrdering.compare(Double.NaN, Double.PositiveInfinity) // 1 Ordering.Double.TotalOrdering.compare(0.0, Double.NaN) // -1 Ordering.Double.TotalOrdering.compare(Double.PositiveInfinity, Double.NaN) // -1
ソート
Java
ソートするときは、正負のゼロは区別されます。NaNは最後に並びます。
var arr = new Double[]{Double.NaN, -1.0, 0.0, -0.0, 1.0}; java.util.Arrays.sort(arr); // => -1.0, -0.0, 0.0, 1.0, NaN
Scala
ScalaでソートしてもJavaと同じソート結果になります。
import Ordering.Double.TotalOrdering
または
import Ordering.Double.IeeeOrdering
どちらかをインポートする必要があります。
インポートしないと
warning: object DeprecatedDoubleOrdering in object Ordering is deprecated (since 2.13.0): There are multiple ways to order Doubles (Ordering.Double.TotalOrdering, Ordering.Double.IeeeOrdering). Specify one by using a local import, assigning an implicit val, or passing it explicitly. See the documentation for details.
という警告が表示されます。
どちらをインポートしてもソートするだけであれば同じです。
ソートではなく minやmaxメソッドでは2つのOrderingのどちらをインポートするかによって結果が変わってきます。
val seq = List(Double.NaN, -1.0, 0.0, -0.0, 1.0) { import Ordering.Double.IeeeOrdering println(seq.sorted) // List(-1.0, -0.0, 0.0, 1.0, NaN) // Javaと同じ結果 println(seq.min) // NaN <- minは上と結果が違う println(seq.max) // NaN <- maxは上と同じ } { import Ordering.Double.TotalOrdering println(seq.sorted) // List(-1.0, -0.0, 0.0, 1.0, NaN) // Javaと同じ結果 println(seq.min) // -1.0 println(seq.max) // NaN }
sortedメソッドは内部ではOrderingのcompareメソッドで比較しています。
min, maxメソッドは内部ではOrderingのmin, maxメソッドで比較しています。
Scalaでの2つのOrdering
IeeeOrdering
IeeeOrdering.compareメソッドはJavaのDouble.compareを呼び出しており、同じ結果になります。つまり0.0は-0.0より大きく、NaNは正の無限大よりも大きいです。
IeeeOrderingのgt, gteq, lt, lteq, equivメソッドはJavaの比較演算子と同じ結果になります。つまり0.0と-0.0は同じ値で、NaNはなにと比較しても常にfalse、!=は常にtrueになります。
IeeeOrderingのmax, minメソッドはjava.lang.Math.max, java.lang.Math.minを呼び出しており、どちらかもしくは2つともNaNであれば、NaNを返します。
TotalOrdering
全順序というものです。浮動小数点数のすべての数を並べることができます。IeeeOrderingのようにNaNや正負のゼロの例外的な挙動がありません。
TotalOrdering.compareメソッドはJavaのDouble.compareを呼び出しており、同じ結果になります。つまり0.0は-0.0より大きく、NaNは正の無限大よりも大きいです。
TotalOrderingのgt, gteq, lt, lteq, equivメソッドもJavaのDouble.compareメソッドと同じ結果になります。つまり0.0は-0.0より大きく、NaNは正の無限大よりも大きいです。
TotalOrderingのmax, minメソッドは以下のような定義になっており、0.0は-0.0より大きく、NaNは正の無限大よりも大きい扱いです。
def max(x: U, y: U): U = if (gteq(x, y)) x else y def min(x: U, y: U): U = if (lteq(x, y)) x else y
以上。