次の方法で共有


System.Single 構造体

この記事では、この API のリファレンス ドキュメントに補足的な解説を提供します。

Single 値型は、負の 3.402823e38 から正の 3.402823e38 までの値と、正または負のゼロ、PositiveInfinityNegativeInfinity、および非数 (NaN) を含む、単精度 32 ビット数値を表します。 これは、非常に大きい値 (惑星や銀河間の距離など) または非常に小さい値 (1 キロ単位の物質の分子質量など) を表し、多くの場合、不正確な値 (地球から別の太陽系までの距離など) を表すことを目的としています。 Single型は、二項浮動小数点演算の IEC 60559:1989 (IEEE 754) 標準に準拠しています。

System.Single には、この型のインスタンスを比較するメソッド、インスタンスの値を文字列形式に変換するメソッド、数値の文字列表現をこの型のインスタンスに変換するメソッドが用意されています。 書式指定コードが値型の文字列形式を制御する方法については、「書式指定型標準数値書式指定文字列、およびカスタム数値書式指定文字列」を参照してください。

浮動小数点表現と精度

Single データ型は、次の表に示すように、単精度浮動小数点値を 32 ビットバイナリ形式で格納します。

パーツ ビット
仮数 (Significand/mantissa) 0-22
指数 23-30
符号 (0 = 正、1 = 負) 31

小数部が一部の小数部の値 (1/3 や Math.PIなど) を正確に表すことができないのと同様に、二項分数は一部の小数部を表すことができません。 たとえば、2/10 は 10 進小数として .2 で正確に表され、.0011111001001100 で二項分数として表され、パターン "1100" は無限大に繰り返されます。 この場合、浮動小数点値は、それが表す数値の不正確な表現を提供します。 元の浮動小数点値に対して追加の算術演算を実行すると、多くの場合、精度が不足します。 たとえば、.3 を 10 で乗算し、.3 を .3 に 9 回加算した結果を比較すると、乗算よりも 8 つの演算が含まれるため、加算の結果の精度が低くなります。 この差異は、"R" Singleを使用して 2 つの値を表示する場合にのみ明らかであり、必要に応じて、Single型でサポートされている有効桁数の 9 桁すべてが表示されます。

using System;

public class Example12
{
    public static void Main()
    {
        Single value = .2f;
        Single result1 = value * 10f;
        Single result2 = 0f;
        for (int ctr = 1; ctr <= 10; ctr++)
            result2 += value;

        Console.WriteLine($".2 * 10:           {result1:R}");
        Console.WriteLine($".2 Added 10 times: {result2:R}");
    }
}
// The example displays the following output:
//       .2 * 10:           2
//       .2 Added 10 times: 2.00000024
let value = 0.2f
let result1 = value * 10f
let mutable result2 = 0f
for _ = 1 to 10 do
    result2 <- result2 + value

printfn $".2 * 10:           {result1:R}"
printfn $".2 Added 10 times: {result2:R}"
// The example displays the following output:
//       .2 * 10:           2
//       .2 Added 10 times: 2.00000024
Module Example13
    Public Sub Main()
        Dim value As Single = 0.2
        Dim result1 As Single = value * 10
        Dim result2 As Single
        For ctr As Integer = 1 To 10
            result2 += value
        Next
        Console.WriteLine(".2 * 10:           {0:R}", result1)
        Console.WriteLine(".2 Added 10 times: {0:R}", result2)
    End Sub
End Module
' The example displays the following output:
'       .2 * 10:           2
'       .2 Added 10 times: 2.00000024

一部の数値は小数部の二項値として正確に表すことができないため、浮動小数点数は実数のみを近似できます。

すべての浮動小数点数には有効桁数が制限されており、浮動小数点値が実数にどの程度正確に近似されるかも決定されます。 Single値の有効桁数は最大 7 桁ですが、内部的には最大 9 桁が維持されます。 つまり、一部の浮動小数点演算では、浮動小数点値を変更する精度が不足している可能性があります。 次の例では、大きな単精度浮動小数点値を定義し、これに Single.Epsilon と 1,000兆の積を加えています。 ただし、製品が小さすぎて元の浮動小数点値を変更できません。 その最下位桁は 1000 分の 1 ですが、製品の最も重要な数字は 10 から 30 です

using System;

public class Example13
{
    public static void Main()
    {
        Single value = 123.456f;
        Single additional = Single.Epsilon * 1e15f;
        Console.WriteLine($"{value} + {additional} = {value + additional}");
    }
}
// The example displays the following output:
//    123.456 + 1.401298E-30 = 123.456
open System

let value = 123.456f
let additional = Single.Epsilon * 1e15f
printfn $"{value} + {additional} = {value + additional}"
// The example displays the following output:
//    123.456 + 1.401298E-30 = 123.456
Module Example
   Public Sub Main()
      Dim value As Single = 123.456
      Dim additional As Single = Single.Epsilon * 1e15
      Console.WriteLine($"{value} + {additional} = {value + additional}")
   End Sub
End Module
' The example displays the following output:
'   123.456 + 1.401298E-30 = 123.456

浮動小数点数の有効桁数が制限されている場合、次のような結果が生じることがあります。

  • 特定の精度で等しく見える2つの浮動小数点数は、その最下位の桁が異なるため、等しいと比較されない場合があります。 次の例では、一連の数値が一緒に追加され、その合計が予想される合計と比較されます。 2 つの値は同じであるように見えますが、 Equals メソッドの呼び出しは、同じではないことを示します。

    using System;
    
    public class Example9
    {
        public static void Main()
        {
            Single[] values = { 10.01f, 2.88f, 2.88f, 2.88f, 9.0f };
            Single result = 27.65f;
            Single total = 0f;
            foreach (var value in values)
                total += value;
    
            if (total.Equals(result))
                Console.WriteLine("The sum of the values equals the total.");
            else
                Console.WriteLine($"The sum of the values ({total}) does not equal the total ({result}).");
        }
    }
    // The example displays the following output:
    //      The sum of the values (27.65) does not equal the total (27.65).   
    //
    // If the index items in the Console.WriteLine statement are changed to {0:R},
    // the example displays the following output:
    //       The sum of the values (27.6500015) does not equal the total (27.65).
    
    let values = [| 10.01f; 2.88f; 2.88f; 2.88f; 9f |]
    let result = 27.65f
    let mutable total = 0f
    for value in values do
        total <- total + value
    
    if total.Equals result then
        printfn "The sum of the values equals the total."
    else
        printfn "The sum of the values ({total}) does not equal the total ({result})."
    // The example displays the following output:
    //      The sum of the values (27.65) does not equal the total (27.65).   
    //
    // If the index items in the Console.WriteLine statement are changed to {0:R},
    // the example displays the following output:
    //       The sum of the values (27.6500015) does not equal the total (27.65).
    
    Module Example10
        Public Sub Main()
            Dim values() As Single = {10.01, 2.88, 2.88, 2.88, 9.0}
            Dim result As Single = 27.65
            Dim total As Single
            For Each value In values
                total += value
            Next
            If total.Equals(result) Then
                Console.WriteLine("The sum of the values equals the total.")
            Else
                Console.WriteLine("The sum of the values ({0}) does not equal the total ({1}).",
                               total, result)
            End If
        End Sub
    End Module
    ' The example displays the following output:
    '      The sum of the values (27.65) does not equal the total (27.65).   
    '
    ' If the index items in the Console.WriteLine statement are changed to {0:R},
    ' the example displays the following output:
    '       The sum of the values (27.639999999999997) does not equal the total (27.64).
    

    Console.WriteLine(String, Object, Object) ステートメントの書式項目を {0} および {1} から {0:R} に変更し、2 つの{1:R}値のすべての有効桁数を表示するようにSingleする場合、加算操作中に精度が失われるため、2 つの値が等しくないことは明らかです。 この場合、比較を実行する前に、 Math.Round(Double, Int32) メソッドを呼び出して Single 値を目的の精度に丸めることで問題を解決できます。

  • 浮動小数点数を使用する数学演算または比較演算では、10 進数を使用した場合、2 進浮動小数点数が 10 進数と等しくない可能性があるため、同じ結果が得られない可能性があります。 前の例では、.3 に 10 を乗算し、.3 を .3 に 9 回加算した結果を表示します。

    小数部の値を持つ数値演算の精度が重要な場合は、Decimal型ではなくSingle型を使用します。 Int64型またはUInt64型の範囲を超える整数値を持つ数値演算の精度が重要な場合は、BigInteger型を使用します。

  • 浮動小数点数が関係している場合、値は ラウンドトリップ しない可能性があります。 演算によって元の浮動小数点数が別の形式に変換され、逆演算によって変換されたフォームが浮動小数点数に変換され、最終的な浮動小数点数が元の浮動小数点数と等しい場合、値はラウンドトリップと言われます。 変換で 1 つ以上の最下位桁が失われたり変更されたりするため、ラウンド トリップが失敗する可能性があります。

    次の例では、3 つの Single 値が文字列に変換され、ファイルに保存されます。 .NET Framework でこの例を実行した場合、値が同じであるように見えても、復元された値は元の値と等しくありません。 (この問題は、値が正しく往復されるようになった .NET で対処されました)。

    StreamWriter sw = new(@"./Singles.dat");
    float[] values = { 3.2f / 1.11f, 1.0f / 3f, (float)Math.PI };
    for (int ctr = 0; ctr < values.Length; ctr++)
    {
        sw.Write(values[ctr].ToString());
        if (ctr != values.Length - 1)
            sw.Write("|");
    }
    sw.Close();
    
    float[] restoredValues = new float[values.Length];
    StreamReader sr = new(@"./Singles.dat");
    string temp = sr.ReadToEnd();
    string[] tempStrings = temp.Split('|');
    for (int ctr = 0; ctr < tempStrings.Length; ctr++)
        restoredValues[ctr] = float.Parse(tempStrings[ctr]);
    
    for (int ctr = 0; ctr < values.Length; ctr++)
        Console.WriteLine($"{values[ctr]} {(values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>")} {restoredValues[ctr]}");
    
    // The example displays the following output:
    //       2.882883 <> 2.882883
    //       0.3333333 <> 0.3333333
    //       3.141593 <> 3.141593
    
    open System
    open System.IO
    
    let values = [| 3.2f / 1.11f; 1f / 3f; MathF.PI |]
    
    do
        use sw = new StreamWriter(@".\Singles.dat")
        for i = 0 to values.Length - 1 do
            sw.Write(string values[i])
            if i <> values.Length - 1 then
                sw.Write "|"
    
    let restoredValues =
        use sr = new StreamReader(@".\Singles.dat")
        sr.ReadToEnd().Split '|'
        |> Array.map Single.Parse
    
    for i = 0 to values.Length - 1 do
        printfn $"""{values[i]} {if values[i].Equals restoredValues[i] then "=" else "<>"} {restoredValues[i]}"""
                        
    // The example displays the following output:
    //       2.882883 <> 2.882883
    //       0.3333333 <> 0.3333333
    //       3.141593 <> 3.141593
    
    Imports System.IO
    
    Module Example11
        Public Sub Main()
            Dim sw As New StreamWriter(".\Singles.dat")
            Dim values() As Single = {3.2 / 1.11, 1.0 / 3, CSng(Math.PI)}
            For ctr As Integer = 0 To values.Length - 1
                sw.Write(values(ctr).ToString())
                If ctr <> values.Length - 1 Then sw.Write("|")
            Next
            sw.Close()
    
            Dim restoredValues(values.Length - 1) As Single
            Dim sr As New StreamReader(".\Singles.dat")
            Dim temp As String = sr.ReadToEnd()
            Dim tempStrings() As String = temp.Split("|"c)
            For ctr As Integer = 0 To tempStrings.Length - 1
                restoredValues(ctr) = Single.Parse(tempStrings(ctr))
            Next
    
            For ctr As Integer = 0 To values.Length - 1
                Console.WriteLine("{0} {2} {1}", values(ctr),
                               restoredValues(ctr),
                               If(values(ctr).Equals(restoredValues(ctr)), "=", "<>"))
            Next
        End Sub
    End Module
    ' The example displays the following output:
    '        2.882883 <> 2.882883
    '        0.3333333 <> 0.3333333
    '        3.141593 <> 3.141593
    

    .NET Framework を対象とする場合は、"G9" 標準数値書式文字列を使用して Single 値の完全な精度を保持することで、値を正常にラウンドトリップできます。

  • Single 値の精度は、 Double 値よりも小さくなります。 一見同等のSingleに変換されるDouble値は、多くの場合、精度の違いのためにDouble値と等しくありません。 次の例では、同じ除算操作の結果が Double 値と Single 値に割り当てられます。 Single値がDoubleにキャストされた後、2 つの値を比較すると、それらが等しくないことが示されます。

    using System;
    
    public class Example9
    {
        public static void Main()
        {
            Double value1 = 1 / 3.0;
            Single sValue2 = 1 / 3.0f;
            Double value2 = (Double)sValue2;
            Console.WriteLine($"{value1:R} = {value2:R}: {value1.Equals(value2)}");
        }
    }
    // The example displays the following output:
    //        0.33333333333333331 = 0.3333333432674408: False
    
    open System
    
    let value1 = 1. / 3.
    let sValue2 = 1f /3f
    
    let value2 = double sValue2
    printfn $"{value1:R} = {value2:R}: {value1.Equals value2}"
    // The example displays the following output:
    //        0.33333333333333331 = 0.3333333432674408: False
    
    Module Example10
        Public Sub Main()
            Dim value1 As Double = 1 / 3
            Dim sValue2 As Single = 1 / 3
            Dim value2 As Double = CDbl(sValue2)
            Console.WriteLine("{0} = {1}: {2}", value1, value2, value1.Equals(value2))
        End Sub
    End Module
    ' The example displays the following output:
    '       0.33333333333333331 = 0.3333333432674408: False
    

    この問題を回避するには、Double データ型の代わりに Single データ型を使用するか、両方の値の有効桁数が同じになるように Round メソッドを使用します。

等しいかどうかをテストする

等しいと見なすには、2 つの Single 値が同じ値を表す必要があります。 ただし、値間の精度の違い、または一方または両方の値による精度の損失により、同一であると予想される浮動小数点値は、最下位の桁数の違いにより等しくないことがよくあります。 その結果、 Equals メソッドを呼び出して 2 つの値が等しいかどうかを判断したり、 CompareTo メソッドを呼び出して 2 つの Single 値間の関係を判断したりすると、多くの場合、予期しない結果が生じます。 これは、次の例で明らかに等しい 2 つの Single 値が等しくないことがわかります。最初の値の有効桁数は 7 桁で、2 番目の値は 9 であるためです。

using System;

public class Example
{
   public static void Main()
   {
      float value1 = .3333333f;
      float value2 = 1.0f/3;
      Console.WriteLine($"{value1:R} = {value2:R}: {value1.Equals(value2)}");
   }
}
// The example displays the following output:
//        0.3333333 = 0.333333343: False
let value1 = 0.3333333f
let value2 = 1f / 3f
printfn $"{value1:R} = {value2:R}: {value1.Equals value2}"
// The example displays the following output:
//        0.3333333 = 0.333333343: False
Module Example1
    Public Sub Main()
        Dim value1 As Single = 0.3333333
        Dim value2 As Single = 1 / 3
        Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2))
    End Sub
End Module
' The example displays the following output:
'       0.3333333 = 0.333333343: False

さまざまなコード パスに従い、さまざまな方法で操作される計算値は、多くの場合、等しくないことが証明されます。 次の例では、1 つの Single 値が 2 乗され、元の値を復元するために平方根が計算されます。 2 番目の Single に 3.51 を乗算し、結果の平方根を 3.51 で除算して元の値を復元する前に 2 乗します。 2 つの値は同じであるように見えますが、 Equals(Single) メソッドの呼び出しは、それらが等しくないことを示します。 "G9" 標準書式指定文字列を使用して、各 Single 値のすべての有効桁数を表示する結果文字列を返すと、2 番目の値が 1 番目の値より .0000000000001小さいことが示されます。

using System;

public class Example1
{
    public static void Main()
    {
        float value1 = 10.201438f;
        value1 = (float)Math.Sqrt((float)Math.Pow(value1, 2));
        float value2 = (float)Math.Pow((float)value1 * 3.51f, 2);
        value2 = ((float)Math.Sqrt(value2)) / 3.51f;
        Console.WriteLine($"{value1} = {value2}: {value1.Equals(value2)}");
        Console.WriteLine();
        Console.WriteLine($"{value1:G9} = {value2:G9}");
    }
}
// The example displays the following output:
//       10.20144 = 10.20144: False
//       
//       10.201438 = 10.2014389
let value1 = 
    10.201438f ** 2f
    |> sqrt

let value2 =
   ((value1 * 3.51f) ** 2f |> sqrt) / 3.51f

printfn $"{value1} = {value2}: {value1.Equals value2}\n" 
printfn $"{value1:G9} = {value2:G9}"
// The example displays the following output:
//       10.20144 = 10.20144: False
//       
//       10.201438 = 10.2014389
Module Example2
    Public Sub Main()
        Dim value1 As Single = 10.201438
        value1 = CSng(Math.Sqrt(CSng(Math.Pow(value1, 2))))
        Dim value2 As Single = CSng(Math.Pow(value1 * CSng(3.51), 2))
        value2 = CSng(Math.Sqrt(value2) / CSng(3.51))
        Console.WriteLine("{0} = {1}: {2}",
                        value1, value2, value1.Equals(value2))
        Console.WriteLine()
        Console.WriteLine("{0:G9} = {1:G9}", value1, value2)
    End Sub
End Module
' The example displays the following output:
'       10.20144 = 10.20144: False
'       
'       10.201438 = 10.2014389

精度の低下が比較の結果に影響する可能性がある場合は、 Equals または CompareTo メソッドを呼び出す代わりに、次の手法を使用できます。

  • Math.Round メソッドを呼び出して、両方の値の有効桁数が同じであることを確認します。 次の例では、2 つの小数部の値が同等になるように、この方法を使用するように前の例を変更します。

    using System;
    
    public class Example2
    {
        public static void Main()
        {
            float value1 = .3333333f;
            float value2 = 1.0f / 3;
            int precision = 7;
            value1 = (float)Math.Round(value1, precision);
            value2 = (float)Math.Round(value2, precision);
            Console.WriteLine($"{value1:R} = {value2:R}: {value1.Equals(value2)}");
        }
    }
    // The example displays the following output:
    //        0.3333333 = 0.3333333: True
    
    open System
    
    let value1 = 0.3333333f
    let value2 = 1f / 3f
    let precision = 7
    let value1r = Math.Round(float value1, precision) |> float32
    let value2r = Math.Round(float value2, precision) |> float32
    printfn $"{value1:R} = {value2:R}: {value1.Equals value2}"
    // The example displays the following output:
    //        0.3333333 = 0.3333333: True
    
    Module Example3
        Public Sub Main()
            Dim value1 As Single = 0.3333333
            Dim value2 As Single = 1 / 3
            Dim precision As Integer = 7
            value1 = CSng(Math.Round(value1, precision))
            value2 = CSng(Math.Round(value2, precision))
            Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2))
        End Sub
    End Module
    ' The example displays the following output:
    '       0.3333333 = 0.3333333: True
    

    精度の問題は、引き続き中間値の丸めにも適用されます。 詳細については、 Math.Round(Double, Int32, MidpointRounding) メソッドを参照してください。

  • 等値ではなく近似等価性をテストします。 この手法では、2 つの値が異なるが等しい場合は絶対量を定義するか、小さい値が大きい値から分岐できる相対量を定義する必要があります。

    警告

    Single.Epsilon は、等しいかどうかをテストするときに、2 つの Single 値間の距離の絶対メジャーとして使用される場合があります。 ただし、 Single.Epsilon は、値が 0 の Single に加算または減算できる、可能な限り小さい値を測定します。 ほとんどの正と負の Single 値では、 Single.Epsilon の値が小さすぎて検出できません。 したがって、0 の値を除き、等しいかどうかをテストで使用することはお勧めしません。

    次の例では、後者のアプローチを使用して、2 つの値の相対差をテストする IsApproximatelyEqual メソッドを定義します。 また、 IsApproximatelyEqual メソッドと Equals(Single) メソッドの呼び出しの結果も比較します。

    using System;
    
    public class Example3
    {
        public static void Main()
        {
            float one1 = .1f * 10;
            float one2 = 0f;
            for (int ctr = 1; ctr <= 10; ctr++)
                one2 += .1f;
    
            Console.WriteLine($"{one1:R} = {one2:R}: {one1.Equals(one2)}");
            Console.WriteLine($"{one1:R} is approximately equal to {one2:R}: " +
                $"{IsApproximatelyEqual(one1, one2, .000001f)}");
            
            float negativeOne1 = -1 * one1;
            float negativeOne2 = -1 * one2;
    
            Console.WriteLine($"{negativeOne1:R} = {negativeOne2:R}: {negativeOne1.Equals(negativeOne2)}");
            Console.WriteLine($"{negativeOne1:R} is approximately equal to {negativeOne2:R}: " +
                $"{IsApproximatelyEqual(negativeOne1, negativeOne2, .000001f)}");
        }
    
        static bool IsApproximatelyEqual(float value1, float value2, float epsilon)
        {
            // If they are equal anyway, just return True.
            if (value1.Equals(value2))
                return true;
    
            // Handle NaN, Infinity.
            if (Double.IsInfinity(value1) | Double.IsNaN(value1))
                return value1.Equals(value2);
            else if (Double.IsInfinity(value2) | Double.IsNaN(value2))
                return value1.Equals(value2);
    
            // Handle zero to avoid division by zero
            double divisor = Math.Max(value1, value2);
            if (divisor.Equals(0))
                divisor = Math.Min(value1, value2);
    
            return Math.Abs((value1 - value2) / divisor) <= epsilon;
        }
    }
    // The example displays the following output:
    //       1 = 1.00000012: False
    //       1 is approximately equal to 1.00000012: True
    //       -1 is approximately equal to -1.00000012: True
    
    open System
    
    let isApproximatelyEqual value1 value2 epsilon =
        // If they are equal anyway, just return True.
        if value1.Equals value2 then 
            true
        // Handle NaN, Infinity.
        elif Single.IsInfinity value1 || Single.IsNaN value1 then
            value1.Equals value2
        elif Single.IsInfinity value2 || Single.IsNaN value2 then
            value1.Equals value2
        else
            // Handle zero to avoid division by zero
            let divisor = max value1 value2
            let divisor = 
                if divisor.Equals 0 then
                    min value1 value2
                else divisor
            abs (value1 - value2) / divisor <= epsilon           
    
    
    let one1 = 0.1f * 10f
    let mutable one2 = 0f
    for _ = 1 to 10 do
       one2 <- one2 + 0.1f
    
    printfn $"{one1:R} = {one2:R}: {one1.Equals one2}"
    printfn $"{one1:R} is approximately equal to {one2:R}: {isApproximatelyEqual one1 one2 0.000001f}" 
    // The example displays the following output:
    //       1 = 1.00000012: False
    //       1 is approximately equal to 1.00000012: True
    
    Module Example4
        Public Sub Main()
            Dim one1 As Single = 0.1 * 10
            Dim one2 As Single = 0
            For ctr As Integer = 1 To 10
                one2 += CSng(0.1)
            Next
            Console.WriteLine("{0:R} = {1:R}: {2}", one1, one2, one1.Equals(one2))
            Console.WriteLine("{0:R} is approximately equal to {1:R}: {2}",
                            one1, one2,
                            IsApproximatelyEqual(one1, one2, 0.000001))
        End Sub
    
        Function IsApproximatelyEqual(value1 As Single, value2 As Single,
                                     epsilon As Single) As Boolean
            ' If they are equal anyway, just return True.
            If value1.Equals(value2) Then Return True
    
            ' Handle NaN, Infinity.
            If Single.IsInfinity(value1) Or Single.IsNaN(value1) Then
                Return value1.Equals(value2)
            ElseIf Single.IsInfinity(value2) Or Single.IsNaN(value2) Then
                Return value1.Equals(value2)
            End If
    
            ' Handle zero to avoid division by zero
            Dim divisor As Single = Math.Max(value1, value2)
            If divisor.Equals(0) Then
                divisor = Math.Min(value1, value2)
            End If
    
            Return Math.Abs(value1 - value2) / divisor <= epsilon
        End Function
    End Module
    ' The example displays the following output:
    '       1 = 1.00000012: False
    '       1 is approximately equal to 1.00000012: True
    

浮動小数点値と例外

浮動小数点値を持つ操作は、整数型を使用する操作とは異なり、例外をスローしません。これは、ゼロによる除算やオーバーフローなどの無効な操作の場合に例外をスローします。 代わりに、このような状況では、浮動小数点演算の結果は、ゼロ、正の無限大、負の無限大、または数値 (NaN) ではありません。

  • 浮動小数点演算の結果が変換先の形式に対して小さすぎる場合、結果は 0 になります。 これは、次の例に示すように、2 つの非常に小さな浮動小数点数が乗算されるときに発生する可能性があります。

    using System;
    
    public class Example6
    {
        public static void Main()
        {
            float value1 = 1.163287e-36f;
            float value2 = 9.164234e-25f;
            float result = value1 * value2;
            Console.WriteLine($"{value1} * {value2} = {result}");
            Console.WriteLine($"{result} = 0: {result.Equals(0.0f)}");
        }
    }
    // The example displays the following output:
    //       1.163287E-36 * 9.164234E-25 = 0
    //       0 = 0: True
    
    let value1 = 1.163287e-36f
    let value2 = 9.164234e-25f
    let result = value1 * value2
    printfn $"{value1} * {value2} = {result}"
    printfn $"{result} = 0: {result.Equals(0f)}"
    // The example displays the following output:
    //       1.163287E-36 * 9.164234E-25 = 0
    //       0 = 0: True
    
    Module Example7
        Public Sub Main()
            Dim value1 As Single = 1.163287E-36
            Dim value2 As Single = 9.164234E-25
            Dim result As Single = value1 * value2
            Console.WriteLine("{0} * {1} = {2:R}", value1, value2, result)
            Console.WriteLine("{0} = 0: {1}", result, result.Equals(0))
        End Sub
    End Module
    ' The example displays the following output:
    '       1.163287E-36 * 9.164234E-25 = 0
    '       0 = 0: True
    
  • 浮動小数点演算の結果の大きさが変換先の形式の範囲を超えた場合、結果の符号に応じて、操作の結果は PositiveInfinity または NegativeInfinityされます。 次の例に示すように、 Single.MaxValue オーバーフローする操作の結果が PositiveInfinityされ、 Single.MinValue オーバーフローした操作の結果が NegativeInfinityされます。

    using System;
    
    public class Example7
    {
        public static void Main()
        {
            float value1 = 3.065e35f;
            float value2 = 6.9375e32f;
            float result = value1 * value2;
            Console.WriteLine($"PositiveInfinity: {Single.IsPositiveInfinity(result)}");
            Console.WriteLine($"NegativeInfinity: {Single.IsNegativeInfinity(result)}");
            Console.WriteLine();
    
            value1 = -value1;
            result = value1 * value2;
            Console.WriteLine($"PositiveInfinity: {Single.IsPositiveInfinity(result)}");
            Console.WriteLine($"NegativeInfinity: {Single.IsNegativeInfinity(result)}");
        }
    }
    
    // The example displays the following output:
    //       PositiveInfinity: True
    //       NegativeInfinity: False
    //       
    //       PositiveInfinity: False
    //       NegativeInfinity: True
    
    open System
    
    let value1 = 3.065e35f
    let value2 = 6.9375e32f
    let result = value1 * value2
    printfn $"PositiveInfinity: {Single.IsPositiveInfinity result}" 
    printfn $"NegativeInfinity: {Single.IsNegativeInfinity result}\n"
    
    let value3 = -value1
    let result2 = value3 * value2
    printfn $"PositiveInfinity: {Single.IsPositiveInfinity result}" 
    printfn $"NegativeInfinity: {Single.IsNegativeInfinity result}" 
    
    // The example displays the following output:
    //       PositiveInfinity: True
    //       NegativeInfinity: False
    //       
    //       PositiveInfinity: False
    //       NegativeInfinity: True
    
    Module Example8
        Public Sub Main()
            Dim value1 As Single = 3.065E+35
            Dim value2 As Single = 6.9375E+32
            Dim result As Single = value1 * value2
            Console.WriteLine("PositiveInfinity: {0}",
                             Single.IsPositiveInfinity(result))
            Console.WriteLine("NegativeInfinity: {0}",
                            Single.IsNegativeInfinity(result))
            Console.WriteLine()
            value1 = -value1
            result = value1 * value2
            Console.WriteLine("PositiveInfinity: {0}",
                             Single.IsPositiveInfinity(result))
            Console.WriteLine("NegativeInfinity: {0}",
                            Single.IsNegativeInfinity(result))
        End Sub
    End Module
    ' The example displays the following output:
    '       PositiveInfinity: True
    '       NegativeInfinity: False
    '       
    '       PositiveInfinity: False
    '       NegativeInfinity: True
    

    PositiveInfinity は正の被除数でゼロ除算を行った結果を示し、NegativeInfinity は負の被除数でゼロ除算を行った結果を示します。

  • 浮動小数点演算が無効な場合、操作の結果は NaN。 たとえば、次の操作の結果 NaN します。

    • 0 で除算し、被除数を 0 にします。 ゼロ除算の他のケースでは、 PositiveInfinity または NegativeInfinityが発生します。
    • 入力が無効な浮動小数点演算。 たとえば、負の値の平方根を検索しようとすると、 NaNが返されます。
    • 値が Single.NaN引数を持つすべての操作。

型の変換

Single構造体では、明示的または暗黙的な変換演算子は定義されません。代わりに、変換はコンパイラによって実装されます。

次の表に、他のプリミティブ数値型の値から Single 値への変換の可能性を示します。また、変換が拡大または縮小されているかどうか、および結果の Single の精度が元の値よりも小さいかどうかを示します。

変換 ( 拡大/縮小 精度が失われる可能性があります
Byte 拡大 いいえ
Decimal 拡大

C# にはキャスト演算子が必要であることに注意してください。
はい。 Decimal は 29 桁の有効桁数をサポートします。 Single は 9 をサポートしています。
Double 縮小;範囲外の値は、 Double.NegativeInfinity または Double.PositiveInfinityに変換されます。 はい。 Double は 17 桁の有効桁数をサポートします。 Single は 9 をサポートしています。
Int16 拡大 いいえ
Int32 拡大 はい。 Int32 は 10 桁の有効桁数をサポートします。 Single は 9 をサポートしています。
Int64 拡大 はい。 Int64 は、有効桁数の 19 桁の 10 進数をサポートします。 Single は 9 をサポートしています。
SByte 拡大 いいえ
UInt16 拡大 いいえ
UInt32 拡大 はい。 UInt32 は 10 桁の有効桁数をサポートします。 Single は 9 をサポートしています。
UInt64 拡大 はい。 Int64 は 20 桁の有効桁数をサポートします。 Single は 9 をサポートしています。

次の例では、他のプリミティブ数値型の最小値または最大値を Single 値に変換します。

using System;

public class Example4
{
    public static void Main()
    {
        dynamic[] values = { Byte.MinValue, Byte.MaxValue, Decimal.MinValue,
                           Decimal.MaxValue, Double.MinValue, Double.MaxValue,
                           Int16.MinValue, Int16.MaxValue, Int32.MinValue,
                           Int32.MaxValue, Int64.MinValue, Int64.MaxValue,
                           SByte.MinValue, SByte.MaxValue, UInt16.MinValue,
                           UInt16.MaxValue, UInt32.MinValue, UInt32.MaxValue,
                           UInt64.MinValue, UInt64.MaxValue };
        float sngValue;
        foreach (var value in values)
        {
            if (value.GetType() == typeof(Decimal) ||
                value.GetType() == typeof(Double))
                sngValue = (float)value;
            else
                sngValue = value;
            Console.WriteLine($"{value} ({value.GetType().Name}) --> {sngValue:R} ({sngValue.GetType().Name})");
        }
    }
}
// The example displays the following output:
//       0 (Byte) --> 0 (Single)
//       255 (Byte) --> 255 (Single)
//       -79228162514264337593543950335 (Decimal) --> -7.92281625E+28 (Single)
//       79228162514264337593543950335 (Decimal) --> 7.92281625E+28 (Single)
//       -1.79769313486232E+308 (Double) --> -Infinity (Single)
//       1.79769313486232E+308 (Double) --> Infinity (Single)
//       -32768 (Int16) --> -32768 (Single)
//       32767 (Int16) --> 32767 (Single)
//       -2147483648 (Int32) --> -2.14748365E+09 (Single)
//       2147483647 (Int32) --> 2.14748365E+09 (Single)
//       -9223372036854775808 (Int64) --> -9.223372E+18 (Single)
//       9223372036854775807 (Int64) --> 9.223372E+18 (Single)
//       -128 (SByte) --> -128 (Single)
//       127 (SByte) --> 127 (Single)
//       0 (UInt16) --> 0 (Single)
//       65535 (UInt16) --> 65535 (Single)
//       0 (UInt32) --> 0 (Single)
//       4294967295 (UInt32) --> 4.2949673E+09 (Single)
//       0 (UInt64) --> 0 (Single)
//       18446744073709551615 (UInt64) --> 1.84467441E+19 (Single)
open System

let values: obj list = 
    [ Byte.MinValue; Byte.MaxValue; Decimal.MinValue
      Decimal.MaxValue; Double.MinValue; Double.MaxValue
      Int16.MinValue; Int16.MaxValue; Int32.MinValue
      Int32.MaxValue; Int64.MinValue; Int64.MaxValue
      SByte.MinValue; SByte.MaxValue; UInt16.MinValue
      UInt16.MaxValue; UInt32.MinValue; UInt32.MaxValue
      UInt64.MinValue; UInt64.MaxValue ]

for value in values do
    let sngValue = 
        match value with
        | :? byte as v -> float32 v
        | :? decimal as v -> float32 v
        | :? double as v -> float32 v
        | :? int16 as v -> float32 v
        | :? int as v -> float32 v
        | :? int64 as v -> float32 v
        | :? int8 as v -> float32 v
        | :? uint16 as v -> float32 v
        | :? uint as v -> float32 v
        | :? uint64 as v -> float32 v
        | _ -> raise (NotImplementedException "Unknown Type")
    printfn $"{value} ({value.GetType().Name}) --> {sngValue:R} ({sngValue.GetType().Name})"
// The example displays the following output:
//       0 (Byte) --> 0 (Single)
//       255 (Byte) --> 255 (Single)
//       -79228162514264337593543950335 (Decimal) --> -7.92281625E+28 (Single)
//       79228162514264337593543950335 (Decimal) --> 7.92281625E+28 (Single)
//       -1.79769313486232E+308 (Double) --> -Infinity (Single)
//       1.79769313486232E+308 (Double) --> Infinity (Single)
//       -32768 (Int16) --> -32768 (Single)
//       32767 (Int16) --> 32767 (Single)
//       -2147483648 (Int32) --> -2.14748365E+09 (Single)
//       2147483647 (Int32) --> 2.14748365E+09 (Single)
//       -9223372036854775808 (Int64) --> -9.223372E+18 (Single)
//       9223372036854775807 (Int64) --> 9.223372E+18 (Single)
//       -128 (SByte) --> -128 (Single)
//       127 (SByte) --> 127 (Single)
//       0 (UInt16) --> 0 (Single)
//       65535 (UInt16) --> 65535 (Single)
//       0 (UInt32) --> 0 (Single)
//       4294967295 (UInt32) --> 4.2949673E+09 (Single)
//       0 (UInt64) --> 0 (Single)
//       18446744073709551615 (UInt64) --> 1.84467441E+19 (Single)
Module Example5
    Public Sub Main()
        Dim values() As Object = {Byte.MinValue, Byte.MaxValue, Decimal.MinValue,
                                 Decimal.MaxValue, Double.MinValue, Double.MaxValue,
                                 Int16.MinValue, Int16.MaxValue, Int32.MinValue,
                                 Int32.MaxValue, Int64.MinValue, Int64.MaxValue,
                                 SByte.MinValue, SByte.MaxValue, UInt16.MinValue,
                                 UInt16.MaxValue, UInt32.MinValue, UInt32.MaxValue,
                                 UInt64.MinValue, UInt64.MaxValue}
        Dim sngValue As Single
        For Each value In values
            If value.GetType() = GetType(Double) Then
                sngValue = CSng(value)
            Else
                sngValue = value
            End If
            Console.WriteLine("{0} ({1}) --> {2:R} ({3})",
                           value, value.GetType().Name,
                           sngValue, sngValue.GetType().Name)
        Next
    End Sub
End Module
' The example displays the following output:
'       0 (Byte) --> 0 (Single)
'       255 (Byte) --> 255 (Single)
'       -79228162514264337593543950335 (Decimal) --> -7.92281625E+28 (Single)
'       79228162514264337593543950335 (Decimal) --> 7.92281625E+28 (Single)
'       -1.79769313486232E+308 (Double) --> -Infinity (Single)
'       1.79769313486232E+308 (Double) --> Infinity (Single)
'       -32768 (Int16) --> -32768 (Single)
'       32767 (Int16) --> 32767 (Single)
'       -2147483648 (Int32) --> -2.14748365E+09 (Single)
'       2147483647 (Int32) --> 2.14748365E+09 (Single)
'       -9223372036854775808 (Int64) --> -9.223372E+18 (Single)
'       9223372036854775807 (Int64) --> 9.223372E+18 (Single)
'       -128 (SByte) --> -128 (Single)
'       127 (SByte) --> 127 (Single)
'       0 (UInt16) --> 0 (Single)
'       65535 (UInt16) --> 65535 (Single)
'       0 (UInt32) --> 0 (Single)
'       4294967295 (UInt32) --> 4.2949673E+09 (Single)
'       0 (UInt64) --> 0 (Single)
'       18446744073709551615 (UInt64) --> 1.84467441E+19 (Single)

さらに、Double値はそれぞれDouble.NaNDouble.PositiveInfinity、およびDouble.NegativeInfinitySingle.NaNSingle.PositiveInfinity、およびSingle.NegativeInfinityに変換されます。

一部の数値型の値を Single 値に変換すると、精度が失われる可能性があることに注意してください。 例が示すように、 DecimalDoubleInt32Int64UInt32UInt64 の値を Single 値に変換すると、精度が低下する可能性があります。

Single値からDoubleへの変換は拡大変換です。 Double型にSingle値の正確な表現がない場合、変換によって精度が失われる可能性があります。

Single値からDouble以外のプリミティブ数値データ型の値への変換は縮小変換であり、キャスト演算子 (C#) または変換メソッド (Visual Basic の場合) が必要です。 ターゲット型の MinValue プロパティと MaxValue プロパティによって定義されるターゲット データ型の範囲外の値は、次の表に示すように動作します。

対象の種類 結果
任意の整数型 チェックされたコンテキストで変換が発生した場合の OverflowException 例外。

オフのコンテキスト (C# の既定値) で変換が発生した場合、変換操作は成功しますが、値はオーバーフローします。
Decimal OverflowException の例外

さらに、 Single.NaNSingle.PositiveInfinity、および Single.NegativeInfinity は、チェック されたコンテキスト内の整数への変換の OverflowException をスローしますが、チェックされていないコンテキストで整数に変換すると、これらの値がオーバーフローします。 Decimal への変換では、常に OverflowExceptionがスローされます。 Doubleへの変換では、それぞれDouble.NaNDouble.PositiveInfinity、およびDouble.NegativeInfinityに変換されます。

精度が失われると、 Single 値が別の数値型に変換される可能性があることに注意してください。 整数以外の Single 値を変換する場合、例の出力に示すように、 Single 値が丸められた場合 (Visual Basic の場合と同様)、または切り捨てられた場合 (C# および F# のように) 小数部分が失われます。 Decimal値への変換の場合、Single値にターゲット データ型の正確な表現が含まれていない可能性があります。

次の例では、複数の Single 値を他のいくつかの数値型に変換します。 変換は、Visual Basic (既定)、C# (checked キーワードのため)、F# (open Checked ステートメントのため) のチェックされたコンテキストで発生します。 この例の出力は、チェックされていないコンテキストの両方で変換の結果を示しています。 /removeintchecks+ コンパイラ スイッチを使用してコンパイルし、C# で checked ステートメントをコメントアウトし、F# で open Checked ステートメントをコメントアウトすることで、Visual Basic のチェックされていないコンテキストで変換を実行できます。

using System;

public class Example5
{
    public static void Main()
    {
        float[] values = { Single.MinValue, -67890.1234f, -12345.6789f,
                         12345.6789f, 67890.1234f, Single.MaxValue,
                         Single.NaN, Single.PositiveInfinity,
                         Single.NegativeInfinity };
        checked
        {
            foreach (var value in values)
            {
                try
                {
                    Int64 lValue = (long)value;
                    Console.WriteLine($"{value} ({value.GetType().Name}) --> {lValue} (0x{lValue:X16}) ({lValue.GetType().Name})");
                }
                catch (OverflowException)
                {
                    Console.WriteLine($"Unable to convert {value} to Int64.");
                }
                try
                {
                    UInt64 ulValue = (ulong)value;
                    Console.WriteLine($"{value} ({value.GetType().Name}) --> {ulValue} (0x{ulValue:X16}) ({ulValue.GetType().Name})");
                }
                catch (OverflowException)
                {
                    Console.WriteLine($"Unable to convert {value} to UInt64.");
                }
                try
                {
                    Decimal dValue = (decimal)value;
                    Console.WriteLine($"{value} ({value.GetType().Name}) --> {dValue} ({dValue.GetType().Name})");
                }
                catch (OverflowException)
                {
                    Console.WriteLine($"Unable to convert {value} to Decimal.");
                }

                Double dblValue = value;
                Console.WriteLine($"{value} ({value.GetType().Name}) --> {dblValue} ({dblValue.GetType().Name})");
                Console.WriteLine();
            }
        }
    }
}
// The example displays the following output for conversions performed
// in a checked context:
//       Unable to convert -3.402823E+38 to Int64.
//       Unable to convert -3.402823E+38 to UInt64.
//       Unable to convert -3.402823E+38 to Decimal.
//       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
//
//       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       Unable to convert -67890.13 to UInt64.
//       -67890.13 (Single) --> -67890.12 (Decimal)
//       -67890.13 (Single) --> -67890.125 (Double)
//
//       -12345.68 (Single) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       Unable to convert -12345.68 to UInt64.
//       -12345.68 (Single) --> -12345.68 (Decimal)
//       -12345.68 (Single) --> -12345.6787109375 (Double)
//
//       12345.68 (Single) --> 12345 (0x0000000000003039) (Int64)
//       12345.68 (Single) --> 12345 (0x0000000000003039) (UInt64)
//       12345.68 (Single) --> 12345.68 (Decimal)
//       12345.68 (Single) --> 12345.6787109375 (Double)
//
//       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
//       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
//       67890.13 (Single) --> 67890.12 (Decimal)
//       67890.13 (Single) --> 67890.125 (Double)
//
//       Unable to convert 3.402823E+38 to Int64.
//       Unable to convert 3.402823E+38 to UInt64.
//       Unable to convert 3.402823E+38 to Decimal.
//       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
//
//       Unable to convert NaN to Int64.
//       Unable to convert NaN to UInt64.
//       Unable to convert NaN to Decimal.
//       NaN (Single) --> NaN (Double)
//
//       Unable to convert Infinity to Int64.
//       Unable to convert Infinity to UInt64.
//       Unable to convert Infinity to Decimal.
//       Infinity (Single) --> Infinity (Double)
//
//       Unable to convert -Infinity to Int64.
//       Unable to convert -Infinity to UInt64.
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Single) --> -Infinity (Double)
// The example displays the following output for conversions performed
// in an unchecked context:
//       -3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -3.402823E+38 (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -3.402823E+38 to Decimal.
//       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
//
//       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       -67890.13 (Single) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
//       -67890.13 (Single) --> -67890.12 (Decimal)
//       -67890.13 (Single) --> -67890.125 (Double)
//
//       -12345.68 (Single) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       -12345.68 (Single) --> 18446744073709539271 (0xFFFFFFFFFFFFCFC7) (UInt64)
//       -12345.68 (Single) --> -12345.68 (Decimal)
//       -12345.68 (Single) --> -12345.6787109375 (Double)
//
//       12345.68 (Single) --> 12345 (0x0000000000003039) (Int64)
//       12345.68 (Single) --> 12345 (0x0000000000003039) (UInt64)
//       12345.68 (Single) --> 12345.68 (Decimal)
//       12345.68 (Single) --> 12345.6787109375 (Double)
//
//       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
//       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
//       67890.13 (Single) --> 67890.12 (Decimal)
//       67890.13 (Single) --> 67890.125 (Double)
//
//       3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       3.402823E+38 (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert 3.402823E+38 to Decimal.
//       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
//
//       NaN (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       NaN (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert NaN to Decimal.
//       NaN (Single) --> NaN (Double)
//
//       Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       Infinity (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert Infinity to Decimal.
//       Infinity (Single) --> Infinity (Double)
//
//       -Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -Infinity (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Single) --> -Infinity (Double)
open System
open Checked

let values = 
    [ Single.MinValue; -67890.1234f; -12345.6789f
      12345.6789f; 67890.1234f; Single.MaxValue
      Single.NaN; Single.PositiveInfinity
      Single.NegativeInfinity ]

for value in values do
    try
        let lValue = int64 value
        printfn $"{value} ({value.GetType().Name}) --> {lValue} (0x{lValue:X16}) ({lValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to Int64."
    try
        let ulValue = uint64 value
        printfn $"{value} ({value.GetType().Name}) --> {ulValue} (0x{ulValue:X16}) ({ulValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to UInt64."
    try
        let dValue = decimal value
        printfn $"{value} ({value.GetType().Name}) --> {dValue} ({dValue.GetType().Name})"
    with :? OverflowException ->
        printfn $"Unable to convert {value} to Decimal."

    let dblValue = double value
    printfn $"{value} ({value.GetType().Name}) --> {dblValue} ({dblValue.GetType().Name})\n"
// The example displays the following output for conversions performed
// in a checked context:
//       Unable to convert -3.402823E+38 to Int64.
//       Unable to convert -3.402823E+38 to UInt64.
//       Unable to convert -3.402823E+38 to Decimal.
//       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
//
//       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       Unable to convert -67890.13 to UInt64.
//       -67890.13 (Single) --> -67890.12 (Decimal)
//       -67890.13 (Single) --> -67890.125 (Double)
//
//       -12345.68 (Single) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       Unable to convert -12345.68 to UInt64.
//       -12345.68 (Single) --> -12345.68 (Decimal)
//       -12345.68 (Single) --> -12345.6787109375 (Double)
//
//       12345.68 (Single) --> 12345 (0x0000000000003039) (Int64)
//       12345.68 (Single) --> 12345 (0x0000000000003039) (UInt64)
//       12345.68 (Single) --> 12345.68 (Decimal)
//       12345.68 (Single) --> 12345.6787109375 (Double)
//
//       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
//       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
//       67890.13 (Single) --> 67890.12 (Decimal)
//       67890.13 (Single) --> 67890.125 (Double)
//
//       Unable to convert 3.402823E+38 to Int64.
//       Unable to convert 3.402823E+38 to UInt64.
//       Unable to convert 3.402823E+38 to Decimal.
//       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
//
//       Unable to convert NaN to Int64.
//       Unable to convert NaN to UInt64.
//       Unable to convert NaN to Decimal.
//       NaN (Single) --> NaN (Double)
//
//       Unable to convert Infinity to Int64.
//       Unable to convert Infinity to UInt64.
//       Unable to convert Infinity to Decimal.
//       Infinity (Single) --> Infinity (Double)
//
//       Unable to convert -Infinity to Int64.
//       Unable to convert -Infinity to UInt64.
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Single) --> -Infinity (Double)
// The example displays the following output for conversions performed
// in an unchecked context:
//       -3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -3.402823E+38 (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -3.402823E+38 to Decimal.
//       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
//
//       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
//       -67890.13 (Single) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
//       -67890.13 (Single) --> -67890.12 (Decimal)
//       -67890.13 (Single) --> -67890.125 (Double)
//
//       -12345.68 (Single) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
//       -12345.68 (Single) --> 18446744073709539271 (0xFFFFFFFFFFFFCFC7) (UInt64)
//       -12345.68 (Single) --> -12345.68 (Decimal)
//       -12345.68 (Single) --> -12345.6787109375 (Double)
//
//       12345.68 (Single) --> 12345 (0x0000000000003039) (Int64)
//       12345.68 (Single) --> 12345 (0x0000000000003039) (UInt64)
//       12345.68 (Single) --> 12345.68 (Decimal)
//       12345.68 (Single) --> 12345.6787109375 (Double)
//
//       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
//       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
//       67890.13 (Single) --> 67890.12 (Decimal)
//       67890.13 (Single) --> 67890.125 (Double)
//
//       3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       3.402823E+38 (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert 3.402823E+38 to Decimal.
//       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
//
//       NaN (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       NaN (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert NaN to Decimal.
//       NaN (Single) --> NaN (Double)
//
//       Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       Infinity (Single) --> 0 (0x0000000000000000) (UInt64)
//       Unable to convert Infinity to Decimal.
//       Infinity (Single) --> Infinity (Double)
//
//       -Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
//       -Infinity (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
//       Unable to convert -Infinity to Decimal.
//       -Infinity (Single) --> -Infinity (Double)
Module Example6
    Public Sub Main()
        Dim values() As Single = {Single.MinValue, -67890.1234, -12345.6789,
                                 12345.6789, 67890.1234, Single.MaxValue,
                                 Single.NaN, Single.PositiveInfinity,
                                 Single.NegativeInfinity}
        For Each value In values
            Try
                Dim lValue As Long = CLng(value)
                Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
                               value, value.GetType().Name,
                               lValue, lValue.GetType().Name)
            Catch e As OverflowException
                Console.WriteLine("Unable to convert {0} to Int64.", value)
            End Try
            Try
                Dim ulValue As UInt64 = CULng(value)
                Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
                               value, value.GetType().Name,
                               ulValue, ulValue.GetType().Name)
            Catch e As OverflowException
                Console.WriteLine("Unable to convert {0} to UInt64.", value)
            End Try
            Try
                Dim dValue As Decimal = CDec(value)
                Console.WriteLine("{0} ({1}) --> {2} ({3})",
                               value, value.GetType().Name,
                               dValue, dValue.GetType().Name)
            Catch e As OverflowException
                Console.WriteLine("Unable to convert {0} to Decimal.", value)
            End Try

            Dim dblValue As Double = value
            Console.WriteLine("{0} ({1}) --> {2} ({3})",
                           value, value.GetType().Name,
                           dblValue, dblValue.GetType().Name)
            Console.WriteLine()
        Next
    End Sub
End Module
' The example displays the following output for conversions performed
' in a checked context:
'       Unable to convert -3.402823E+38 to Int64.
'       Unable to convert -3.402823E+38 to UInt64.
'       Unable to convert -3.402823E+38 to Decimal.
'       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
'
'       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
'       Unable to convert -67890.13 to UInt64.
'       -67890.13 (Single) --> -67890.12 (Decimal)
'       -67890.13 (Single) --> -67890.125 (Double)
'
'       -12345.68 (Single) --> -12346 (0xFFFFFFFFFFFFCFC6) (Int64)
'       Unable to convert -12345.68 to UInt64.
'       -12345.68 (Single) --> -12345.68 (Decimal)
'       -12345.68 (Single) --> -12345.6787109375 (Double)
'
'       12345.68 (Single) --> 12346 (0x000000000000303A) (Int64)
'       12345.68 (Single) --> 12346 (0x000000000000303A) (UInt64)
'       12345.68 (Single) --> 12345.68 (Decimal)
'       12345.68 (Single) --> 12345.6787109375 (Double)
'
'       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
'       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
'       67890.13 (Single) --> 67890.12 (Decimal)
'       67890.13 (Single) --> 67890.125 (Double)
'
'       Unable to convert 3.402823E+38 to Int64.
'       Unable to convert 3.402823E+38 to UInt64.
'       Unable to convert 3.402823E+38 to Decimal.
'       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
'
'       Unable to convert NaN to Int64.
'       Unable to convert NaN to UInt64.
'       Unable to convert NaN to Decimal.
'       NaN (Single) --> NaN (Double)
'
'       Unable to convert Infinity to Int64.
'       Unable to convert Infinity to UInt64.
'       Unable to convert Infinity to Decimal.
'       Infinity (Single) --> Infinity (Double)
'
'       Unable to convert -Infinity to Int64.
'       Unable to convert -Infinity to UInt64.
'       Unable to convert -Infinity to Decimal.
'       -Infinity (Single) --> -Infinity (Double)
' The example displays the following output for conversions performed
' in an unchecked context:
'       -3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       -3.402823E+38 (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
'       Unable to convert -3.402823E+38 to Decimal.
'       -3.402823E+38 (Single) --> -3.40282346638529E+38 (Double)
'
'       -67890.13 (Single) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
'       -67890.13 (Single) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
'       -67890.13 (Single) --> -67890.12 (Decimal)
'       -67890.13 (Single) --> -67890.125 (Double)
'
'       -12345.68 (Single) --> -12346 (0xFFFFFFFFFFFFCFC6) (Int64)
'       -12345.68 (Single) --> 18446744073709539270 (0xFFFFFFFFFFFFCFC6) (UInt64)
'       -12345.68 (Single) --> -12345.68 (Decimal)
'       -12345.68 (Single) --> -12345.6787109375 (Double)
'
'       12345.68 (Single) --> 12346 (0x000000000000303A) (Int64)
'       12345.68 (Single) --> 12346 (0x000000000000303A) (UInt64)
'       12345.68 (Single) --> 12345.68 (Decimal)
'       12345.68 (Single) --> 12345.6787109375 (Double)
'
'       67890.13 (Single) --> 67890 (0x0000000000010932) (Int64)
'       67890.13 (Single) --> 67890 (0x0000000000010932) (UInt64)
'       67890.13 (Single) --> 67890.12 (Decimal)
'       67890.13 (Single) --> 67890.125 (Double)
'
'       3.402823E+38 (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       3.402823E+38 (Single) --> 0 (0x0000000000000000) (UInt64)
'       Unable to convert 3.402823E+38 to Decimal.
'       3.402823E+38 (Single) --> 3.40282346638529E+38 (Double)
'
'       NaN (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       NaN (Single) --> 0 (0x0000000000000000) (UInt64)
'       Unable to convert NaN to Decimal.
'       NaN (Single) --> NaN (Double)
'
'       Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       Infinity (Single) --> 0 (0x0000000000000000) (UInt64)
'       Unable to convert Infinity to Decimal.
'       Infinity (Single) --> Infinity (Double)
'
'       -Infinity (Single) --> -9223372036854775808 (0x8000000000000000) (Int64)
'       -Infinity (Single) --> 9223372036854775808 (0x8000000000000000) (UInt64)
'       Unable to convert -Infinity to Decimal.
'       -Infinity (Single) --> -Infinity (Double)

数値型の変換の詳細については、「 .NET での型変換 」および「 型変換テーブル」を参照してください。

浮動小数点機能

Single構造体と関連する型は、次のカテゴリの操作を実行するメソッドを提供します。

  • 値の比較Equals メソッドを呼び出して、2 つのSingle値が等しいかどうかを判断するか、CompareToメソッドを呼び出して 2 つの値間の関係を判断できます。

    Single構造体は、比較演算子の完全なセットもサポートしています。 たとえば、等価性または不等値をテストしたり、1 つの値が別の値より大きいか等しいかを判断することができます。 オペランドの 1 つが Doubleの場合、比較を実行する前に Single 値が Double に変換されます。 オペランドの 1 つが整数型の場合、比較を実行する前に Single に変換されます。 これらは拡大変換ですが、精度が低下する可能性があります。

    警告

    精度の違いにより、等しいと予想される 2 つの Single 値が等しくない場合があり、比較の結果に影響します。 2 つの値の比較の詳細については、「Singleする」セクションを参照してください。

    IsNaNIsInfinityIsPositiveInfinity、およびIsNegativeInfinityメソッドを呼び出して、これらの特別な値をテストすることもできます。

  • 数学演算。 加算、減算、乗算、除算などの一般的な算術演算は、 Single メソッドではなく、言語コンパイラと共通中間言語 (CIL) 命令によって実装されます。 数学演算のもう一方のオペランドが Doubleの場合、 Single は演算を実行する前に Double に変換され、演算の結果も Double 値になります。 もう一方のオペランドが整数型の場合、演算を実行する前に Single に変換され、演算の結果も Single 値になります。

    static クラスでShared (Visual Basic ではSystem.Math) メソッドを呼び出すことで、その他の算術演算を実行できます。 これには、算術 ( Math.AbsMath.SignMath.Sqrtなど)、ジオメトリ ( Math.CosMath.Sinなど)、微積分 ( Math.Log など) に一般的に使用されるその他のメソッドが含まれます。 いずれの場合も、 Single 値は Doubleに変換されます。

    Single値内の個々のビットを操作することもできます。 BitConverter.GetBytes(Single) メソッドは、バイト配列内のビット パターンを返します。 そのバイト配列を BitConverter.ToInt32 メソッドに渡すことで、 Single 値のビット パターンを 32 ビット整数で保持することもできます。

  • 丸め。 丸めは、浮動小数点表現と精度の問題によって生じる値間の差の影響を軽減するための手法としてよく使用されます。 Single メソッドを呼び出すと、Math.Round値を丸めることができます。 ただし、 Single 値はメソッドが呼び出される前に Double に変換され、変換に精度が失われる可能性があることに注意してください。

  • 書式設定Single値を文字列形式に変換するには、ToString メソッドを呼び出すか、複合書式指定機能を使用します。 書式指定文字列が浮動小数点値の文字列表現をどのように制御するかの詳細については、「標準の数値書式指定文字列」および「カスタム数値書式指定文字列」を参照してください。

  • 文字列の解析。 浮動小数点値の文字列形式を Single 値に変換するには、 Parse または TryParse メソッドを呼び出します。 解析操作が失敗した場合、 Parse メソッドは例外をスローしますが、 TryParse メソッドは falseを返します。

  • 型変換Single構造体は、任意の 2 つの標準 .NET データ型間の変換をサポートする、IConvertible インターフェイスの明示的なインターフェイス実装を提供します。 言語コンパイラでは、 Double から Single 値への変換を除き、他のすべての標準数値型の値の暗黙的な変換もサポートされています。 Double以外の標準数値型の値をSingleに変換することは拡大変換であり、キャスト演算子や変換方法を使用する必要はありません。

    ただし、32 ビットと 64 ビットの整数値の変換では、精度が低下する可能性があります。 次の表に、32 ビット、64 ビット、および Double 型の精度の違いを示します。

    タイプ 最大有効桁数 (10 進数) 内部有効桁数 (10 進数)
    Double 15 十七
    Int32UInt32 10 10
    Int64UInt64 19 19
    Single 7 9

    精度の問題は、Single値に変換されるDouble値に最も頻繁に影響します。 次の例では、同一の除算演算によって生成される 2 つの値は等しくありません。値の 1 つは、 Doubleに変換される単精度浮動小数点値であるためです。

    using System;
    
    public class Example8
    {
        public static void Main()
        {
            Double value1 = 1 / 3.0;
            Single sValue2 = 1 / 3.0f;
            Double value2 = (Double)sValue2;
            Console.WriteLine($"{value1:R} = {value2:R}: {value1.Equals(value2)}");
        }
    }
    // The example displays the following output:
    //        0.33333333333333331 = 0.3333333432674408: False
    
    let value1 = 1. / 3.
    let sValue2 = 1f / 3f
    let value2 = double sValue2
    printfn $"{value1:R} = {value2:R}: {value1.Equals value2}"
    // The example displays the following output:
    //        0.33333333333333331 = 0.3333333432674408: False
    
    Module Example9
        Public Sub Main()
            Dim value1 As Double = 1 / 3
            Dim sValue2 As Single = 1 / 3
            Dim value2 As Double = CDbl(sValue2)
            Console.WriteLine("{0} = {1}: {2}", value1, value2, value1.Equals(value2))
        End Sub
    End Module
    ' The example displays the following output:
    '       0.33333333333333331 = 0.3333333432674408: False