|
2019/05/12(Sun) 14:13:23 編集(投稿者)
■No90900 (おばちゃん さん) に返信 > Dim x = 0 / 0 > を計算すると > Double.NaNと値が代入されます。
他にも、 Dim a As Double = +1.0 / 0.0 ' = Double.PositiveInfinity Dim b As Double = -1.0 / 0.0 ' = Double.NegativeInfinity Dim c As Double = a + b とか Dim d As Double = Math.Sqrt(-2.0) などでも NaN 値が算出されます。
> それでは一体Double.NaNという値は何のために存在しているのでしょうか?
IEEE754 に記される通り、文字通りの非数「Not-a-Number」を表すものですね。 無効な演算や、不正な処理が行われたことを表すための値としても利用されます。
https://ja.wikipedia.org/wiki/IEEE_754 https://ja.wikipedia.org/wiki/NaN
計算途中で非数が含まれた場合、その後の演算結果においても、 例外が発生されることなく NaN として伝播されるようになっています。 NaN 値に対して加減乗除どのような演算結果を行おうとも、 結果は NaN のままです。(このような動作を Quiet NaN と言います)
そのため、最終的な演算結果のみを見ることで演算の失敗を判定でき、 演算式の途中で毎回例外処理を行わなくて済むようになります。 .NET Framework や JavaScript における NaN がこれですね。
なお IEEE 754 においては、Quiet NaN とは別に、Signaling NaN という ものが定められています。(ビット列としての表現が異なる) Quiet NaN に対する演算は常に NaN のままとなるのに対し、 Signaling NaN に対する演算は、即時にエラー(あるいは例外)となります。
#If VBC_VER >= 14.0 Then '倍精度浮動小数点数を、ビット列(64bit幅)で表現した場合、 ' 先頭 1 bit は「符号」を表し(0〜1) ' 続く 11 bit は「指数部」を表し(-1022〜1023) ' 残り 52 bit で「仮数部」を表しますが、 'それら【正規化数】とは別に、下記 4 種の特殊値が存在しています。
'====== 浮動小数点数の特殊値 ====== '(1) 指数部と仮数部がすべて 0 の場合、【ゼロ】を意味する。 Dim d0 As Double = BitConverter.ToDouble(BitConverter.GetBytes(&B0__00000000000__0000000000_0000000000_0000000000_0000000000_0000000000_00UL), 0) Dim d1 As Double = BitConverter.ToDouble(BitConverter.GetBytes(&B1__00000000000__0000000000_0000000000_0000000000_0000000000_0000000000_00UL), 0)
'(2) 指数部がすべて 1 の場合、仮数部がすべて 0 なら【無限大】を意味する。 Dim d2 As Double = BitConverter.ToDouble(BitConverter.GetBytes(&B0__11111111111__0000000000_0000000000_0000000000_0000000000_0000000000_00UL), 0) Dim d3 As Double = BitConverter.ToDouble(BitConverter.GetBytes(&B1__11111111111__0000000000_0000000000_0000000000_0000000000_0000000000_00UL), 0)
'(3) 指数部がすべて 1 の場合、仮数部が 0 以外なら【非数】いわゆる NaN を意味する。 Dim d4 As Double = BitConverter.ToDouble(BitConverter.GetBytes(&B0__11111111111__1111111111_1111111111_1111111111_1111111111_1111111111_11UL), 0) Dim d5 As Double = BitConverter.ToDouble(BitConverter.GetBytes(&B1__11111111111__1111111111_1111111111_1111111111_1111111111_1111111111_11UL), 0)
'(4) このほか、指数部がすべて 0、仮数部が 0 以外な【非正規化数】がある。 ' 非正規化数は、正規化数同様に有効な値として扱われるが、数値としての精度は落ちる。
'※非数や非正規化数の場合、仮数部のいずれかの bit が 0 以外であればよいので、実際には上記以外の組み合わせも存在する。
'====== 内容を表示してみる ====== 'ゼロ Console.WriteLine($"d0 = {d0}") '通常のゼロ。CType(Nothing, Double) と同義。 Console.WriteLine($"d1 = {d1}") 'マイナスゼロ(あるいは負の無限小)。d0 = d1 とみなされるが、一部演算では異なる結果となる。 ' Math.IEEERemainder(+1.0, 1.0) の結果は d0 と等しく ' Math.IEEERemainder(-1.0, 1.0) の結果は d1 と等しい。
'ゼロ除算 Console.WriteLine($"1.0 / d0 = {1.0 / d0}") '非ゼロをゼロで割ると、正の無限大となる。 Console.WriteLine($"1.0 / d1 = {1.0 / d1}") '非ゼロをマイナスゼロで割ると、負の無限大となる。
'無限大 Console.WriteLine($"d2 = {d2}") '正の無限大 Console.WriteLine($"d3 = {d3}") '負の無限大
'非数値 Console.WriteLine($"d3 = {d4}") '正符号範囲の非数値 Console.WriteLine($"d5 = {d5}") '負符号範囲の非数値 #End If
|