三流プログラマの戯言

プログラミング初心者が気になったことを書き綴るだけ。主にc#

浮動小数点型(double型)の最小値

みなさんこんにちは、こんなしょうもない記事をもてくれる人は片手で数えれるほどしかいないと思います。

そんなみなさん、こんな疑問を抱いたことはないですか?

浮動小数点型の中で最小の値ってなんだろう?」

と。 ないですかね? 私はないです。

いや、だってdouble.MinValueという値があるじゃないですか。

ちなみに、皆さん答え分かりますか?そう、double.NegativeInfinityがありますね

double.MinValueは最小値なのに、double.NegativInfinityは負の無限大だからいかなる定数よりも小さいはず。果たしてどちらが小さいのか。

ってわけで確認していきましょう。

最小値を出す上でいくつかの数字をピックアップ。

var array = new[]
{
    0,
    double.MinValue,
    double.MaxValue,
    double.Epsilon,
    double.PositiveInfinity,
    double.NegativeInfinity,
    double.NaN
};

MaxValueとかは間違いなく違うのですが、とりあえず入れておきます。

最小値の算出のために以下のメソッドを書きました。

private static double GetMin(double[] array)
{
    var min = array[0];

    for (int i = 1; i < array.Length; i++)
        if (array[i] < min) min = array[i];
            
    return min;
}


private static double GetMin2(double[] array)
{
    var min = array[0];

    for (int i = 1; i < array.Length; i++)
        min = Math.Min(min, array[i]);

    return min;
}

メソッドを二つ用意はしましたが、実行結果は同じになるはずです。

実行のコードは以下の通り。

Console.WriteLine($"Min by MyMethod1 : {GetMin(array)}");
Console.WriteLine($"Min by MyMethod2 : {GetMin2(array)}");

で、気になる実行結果は

Min by MyMethod1 : -∞
Min by MyMethod2 : NaN

あれ?

二つのメソッドで違う答えが出てきました。どういうことでしょう。

これは、Microsoftの設計理念として、NaNはいかなる値よりも小さい値であるというものがあります。*1 ただし比較演算子を使用した場合は、NaNは値を持たないので、常にfalseを返すようになっています。*2 すなわち下記のmin1min2は違う結果になるわけです。

var val = doubel.NaN;
var min1 = (val < min )? val : min;
var min2 = Math.Min(val , min);

ほかの方法で最小値を出すと以下の通りになります。

var sortArray = array.ToArray();
Array.Sort(sortArray);
Console.WriteLine($"Min by Sort      : {sortArray.First()}");
Console.WriteLine($"Min by OrderBy   : {array.OrderBy(p => p).First()}");
Console.WriteLine($"Min by Aggregate : {array.Aggregate((p, q) => Math.Min(p, q))}");
Console.WriteLine($"Min by Aggregate : {array.Aggregate((p, q) => q < p ? q : p)}");
Console.WriteLine($"Min by Min       : {array.Min()}");
Min by Sort      : NaN
Min by OrderBy   : NaN
Min by Aggregate : NaN
Min by Aggregate : -∞
Min by Min       : NaN

double.NaNはいろいろ特殊ですね。 double.NaNの特異性についてもまた書きたいです。

試してないですが、floatも一緒だと思います。

ではまた。

*1:Enamerable.csのMinのソースコードあたりに書いてます。

*2:double.NaN != double.NaNはtrueを返しますが