Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Observação
Este artigo fornece observações complementares à documentação de referência para esta API.
O tipo de valor Single representa um número de 32 bits de precisão única com valores que variam de 3,402823e38 negativos a 3,402823e38 positivos, bem como zero positivo ou negativo, PositiveInfinity, NegativeInfinitye não um número (NaN). Destina-se a representar valores que são extremamente grandes (como distâncias entre planetas ou galáxias) ou extremamente pequenos (como a massa molecular de uma substância em quilogramas) e que muitas vezes são imprecisos (como a distância da Terra a outro sistema solar). O tipo Single está em conformidade com a norma IEC 60559:1989 (IEEE 754) para aritmética binária de ponto flutuante.
System.Single fornece métodos para comparar instâncias desse tipo, converter o valor de uma instância em sua representação de cadeia de caracteres e converter a representação de cadeia de caracteres de um número em uma instância desse tipo. Para obter informações sobre como os códigos de especificação de formato controlam a representação de cadeia de caracteres de tipos de valor, consulte Tipos de formatação, Cadeias de caracteres de formato numérico padrãoe Cadeias de caracteres de formato numérico personalizado.
Representação e precisão de ponto flutuante
O tipo de dados Single armazena valores de ponto flutuante de precisão única em um formato binário de 32 bits, conforme mostrado na tabela a seguir:
| Parte | Bits |
|---|---|
| Significand ou mantissa | 0-22 |
| Expoente | 23-30 |
| Sinal (0 = positivo, 1 = negativo) | 31 |
Assim como as frações decimais são incapazes de representar com precisão alguns valores fracionários (como 1/3 ou Math.PI), as frações binárias são incapazes de representar alguns valores fracionários. Por exemplo, 2/10, que é representado precisamente por .2 como uma fração decimal, é representado por .0011111001001100 como uma fração binária, com o padrão "1100" repetindo ao infinito. Neste caso, o valor de vírgula flutuante fornece uma representação imprecisa do número que representa. A realização de operações matemáticas adicionais sobre o valor original de vírgula flutuante muitas vezes aumenta sua falta de precisão. Por exemplo, se você comparar os resultados de multiplicar .3 por 10 e adicionar .3 a .3 nove vezes, verá que a adição produz o resultado menos preciso, porque envolve oito operações a mais do que a multiplicação. Observe que essa disparidade é aparente apenas se forem exibidos os dois valores Single usando a cadeia de formato numérico padrão "R" , que, se necessário, exibe todos os nove dígitos de precisão suportados pelo tipo Single.
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.0000002
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.0000002
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.0000002
Como alguns números não podem ser representados exatamente como valores binários fracionários, os números de vírgula flutuante só podem se aproximar de números reais.
Todos os números de vírgula flutuante têm um número limitado de dígitos significativos, o que também determina a precisão com que um valor de vírgula flutuante se aproxima de um número real. Um valor Single tem até 7 dígitos decimais de precisão, embora um máximo de 9 dígitos seja mantido internamente. Isso significa que algumas operações de ponto flutuante podem não ter a precisão necessária para alterar um valor de ponto flutuante. O exemplo a seguir define um grande valor de ponto flutuante de precisão única e, em seguida, adiciona o produto de Single.Epsilon e um quatrilhão a ele. No entanto, o produto é demasiado pequeno para modificar o valor em ponto flutuante original. Seu dígito menos significativo é milésimo, enquanto o dígito mais significativo no produto é 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
A imprecisão de um número de ponto flutuante tem várias consequências:
Dois números de vírgula flutuante que parecem iguais para uma determinada precisão podem não ser iguais porque seus dígitos menos significativos são diferentes. No exemplo a seguir, uma série de números é somada e seu total é comparado com o total esperado. Uma chamada ao
Equalsmétodo indica que os valores não são iguais.using System; public class PrecisionList3Example { 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 on .NET: // The sum of the values (27.650002) does not equal the total (27.65). // The example displays the following output on .NET Framework: // The sum of the values (27.65) 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 on .NET: // The sum of the values (27.650002) does not equal the total (27.65). // The example displays the following output on .NET Framework: // The sum of the values (27.65) does not equal the total (27.65).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 ({total}) does not equal the total ({result}).") End If End Sub ' The example displays the following output on .NET: ' The sum of the values (27.650002) does not equal the total (27.65). ' The example displays the following output on .NET Framework: ' The sum of the values (27.65) does not equal the total (27.65).Os dois valores são desiguais devido à perda de precisão durante as operações de adição. Nesse caso, o problema pode ser resolvido chamando o método Math.Round(Double, Int32) para arredondar os valores de Single para a precisão desejada antes de executar a comparação.
Uma operação matemática ou de comparação que usa um número de vírgula flutuante pode não produzir o mesmo resultado se um número decimal for usado, porque o número binário de vírgula flutuante pode não ser igual ao número decimal. Um exemplo anterior ilustrou isso exibindo o resultado de multiplicar .3 por 10 e adicionar .3 a .3 nove vezes.
Quando a precisão em operações numéricas com valores fracionários for importante, use o tipo Decimal em vez do tipo Single. Quando a precisão em operações numéricas com valores integrais além do intervalo dos tipos Int64 ou UInt64 for importante, use o tipo BigInteger.
Um valor pode não de ida e volta se um número de vírgula flutuante estiver envolvido. Diz-se que um valor é de ida e volta se uma operação converte um número de vírgula flutuante original em outra forma, uma operação inversa transforma a forma convertida de volta em um número de vírgula flutuante e o número final de vírgula flutuante é igual ao número de vírgula flutuante original. A viagem de ida e volta pode falhar porque um ou mais dígitos menos significativos são perdidos ou alterados em uma conversão.
No exemplo a seguir, três valores de Single são convertidos em cadeias de caracteres e salvos em um arquivo. Se você executar este exemplo no .NET Framework, mesmo que os valores pareçam ser idênticos, os valores restaurados não são iguais aos valores originais. (Isso já foi abordado no .NET, onde os valores de ida e volta são corretos.)
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 on .NET Framework: // 2.882883 <> 2.882883 // 0.3333333 <> 0.3333333 // 3.141593 <> 3.141593open 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 on .NET Framework: // 2.882883 <> 2.882883 // 0.3333333 <> 0.3333333 // 3.141593 <> 3.141593Dim 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 ' The example displays the following output on .NET Framework: ' 2.882883 <> 2.882883 ' 0.3333333 <> 0.3333333 ' 3.141593 <> 3.141593Se você estiver direcionando o .NET Framework, os valores podem ser arredondados com êxito usando a cadeia de caracteres de formato numérico padrão "G9" para preservar a precisão total dos valores Single.
Single valores têm menos precisão do que Double valores. Um valor Single que é convertido em um Double aparentemente equivalente muitas vezes não é igual ao valor Double devido a diferenças na precisão. No exemplo a seguir, o resultado de operações de divisão idênticas é atribuído a um valor Double e a um valor Single. Depois que o valor Single é convertido em um Double, uma comparação dos dois valores mostra que eles são desiguais.
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: Falseopen 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: FalseModule 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: FalsePara evitar esse problema, use o tipo de dados Double no lugar do tipo de dados Single ou use o método Round para que ambos os valores tenham a mesma precisão.
Teste de igualdade
Para serem considerados iguais, dois valores Single devem representar valores idênticos. No entanto, devido a diferenças de precisão entre os valores, ou devido a uma perda de precisão por um ou ambos os valores, os valores de vírgula flutuante que se espera que sejam idênticos muitas vezes acabam por ser desiguais devido a diferenças nos seus dígitos menos significativos. Como resultado, chamadas para o método Equals para determinar se dois valores são iguais, ou chamadas para o método CompareTo para determinar a relação entre dois valores Single, geralmente produzem resultados inesperados. Isto é evidente no exemplo seguinte, onde dois valores Single aparentemente iguais acabam por ser desiguais, porque o primeiro valor tem 7 dígitos de precisão, enquanto o segundo valor tem 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
Valores calculados que seguem caminhos de código diferentes e que são manipulados de maneiras diferentes geralmente se mostram desiguais. No exemplo a seguir, um valor Single é quadrado e, em seguida, a raiz quadrada é calculada para restaurar o valor original. Um segundo Single é multiplicado por 3,51 e quadrado antes de dividir a raiz quadrada do resultado por 3,51 para restaurar o valor original. Embora os dois valores pareçam ser idênticos, uma chamada para o método Equals(Single) indica que eles não são iguais.
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)}");
// The example displays the following output on .NET:
// 10.201438 = 10.201439: False
// The example displays the following output on .NET Framework:
// 10.20144 = 10.20144: False
let value1 =
10.201438f ** 2f
|> sqrt
let value2 =
((value1 * 3.51f) ** 2f |> sqrt) / 3.51f
printfn $"{value1} = {value2}: {value1.Equals value2}"
// The example displays the following output on .NET:
// 10.201438 = 10.201439: False
// The example displays the following output on .NET Framework:
// 10.20144 = 10.20144: False
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))
' The example displays the following output on .NET:
' 10.201438 = 10.201439: False
' The example displays the following output on .NET Framework:
' 10.20144 = 10.20144: False
Nos casos em que uma perda de precisão provavelmente afetará o resultado de uma comparação, você pode usar as seguintes técnicas em vez de chamar o método Equals ou CompareTo:
Chame o método Math.Round para garantir que ambos os valores tenham a mesma precisão. O exemplo a seguir modifica um exemplo anterior para usar essa abordagem para que dois valores fracionários sejam equivalentes.
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: Trueopen 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: TrueModule 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: TrueO problema da precisão continua a aplicar-se ao arredondamento dos valores médios. Para obter mais informações, consulte o método Math.Round(Double, Int32, MidpointRounding).
Teste para igualdade aproximada em vez de igualdade. Essa técnica requer que você defina uma quantidade absoluta pela qual os dois valores podem diferir, mas ainda assim ser iguais, ou que você defina uma quantidade relativa pela qual o valor menor pode divergir do valor maior.
Advertência
Single.Epsilon às vezes é usado como uma medida absoluta da distância entre dois valores Single ao testar a igualdade. No entanto, Single.Epsilon mede o menor valor possível que pode ser adicionado ou subtraído de um Single cujo valor é zero. Para a maioria dos valores de Single positivos e negativos, o valor de Single.Epsilon é muito pequeno para ser detetado. Portanto, exceto para valores que são zero, não recomendamos seu uso em testes de igualdade.
O exemplo a seguir usa a última abordagem para definir um método
IsApproximatelyEqualque testa a diferença relativa entre dois valores. Ele também contrasta o resultado de chamadas para o métodoIsApproximatelyEquale o método Equals(Single).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 on .NET: // 1 = 1.0000001: False // 1 is approximately equal to 1.0000001: True // -1 = -1.0000001: False // -1 is approximately equal to -1.0000001: Trueopen 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.0000001: False // 1 is approximately equal to 1.0000001: TruePublic 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 ' The example displays the following output: ' 1 = 1.0000001: False ' 1 is approximately equal to 1.0000001: True
Valores de vírgula flutuante e exceções
Operações com valores de ponto flutuante não lançam exceções, ao contrário das operações com tipos integrais, que lançam exceções em casos de operações ilegais, como divisão por zero ou overflow. Em vez disso, nessas situações, o resultado de uma operação de ponto flutuante é zero, infinito positivo, infinito negativo ou não um número (NaN):
Se o resultado de uma operação de ponto flutuante for muito pequeno para o formato de destino, o resultado será zero. Isso pode ocorrer quando dois números de vírgula flutuante muito pequenos são multiplicados, como mostra o exemplo a seguir.
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: Truelet 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: TrueModule 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: TrueSe a magnitude do resultado de uma operação de ponto flutuante exceder a gama do formato de destino, o resultado da operação é PositiveInfinity ou NegativeInfinity, conforme apropriado ao sinal do resultado. O resultado de uma operação que transborda Single.MaxValue é PositiveInfinitye o resultado de uma operação que transborda Single.MinValue é NegativeInfinity, como mostra o exemplo a seguir.
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: Trueopen 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: TrueModule 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: TruePositiveInfinity também resulta de uma divisão por zero com um dividendo positivo, e NegativeInfinity resulta de uma divisão por zero com um dividendo negativo.
Se uma operação de ponto flutuante for inválida, o resultado da operação será NaN. Por exemplo, NaN resulta das seguintes operações:
- Divisão por zero com um dividendo de zero. Note-se que outros casos de divisão por zero resultam em PositiveInfinity ou NegativeInfinity.
- Qualquer operação de ponto flutuante com entrada inválida. Por exemplo, tentar encontrar a raiz quadrada de um valor negativo retorna NaN.
- Qualquer operação com um argumento cujo valor é Single.NaN.
Conversões de tipos
A estrutura Single não define nenhum operador de conversão explícito ou implícito; em vez disso, as conversões são implementadas pelo compilador.
A tabela seguinte lista as possíveis conversões de um valor dos outros tipos numéricos primitivos para um Single valor. Indica também se a conversão está a alargar ou a estreitar e se o resultado Single pode ter menos precisão do que o valor original.
| Conversão de | Alargamento/estreitamento | Possível perda de precisão |
|---|---|---|
| Byte | Alargamento | Não |
| Decimal | Alargamento Observe que o C# requer um operador cast. |
Sim. Decimal suporta 29 dígitos decimais de precisão; Single suporta 9. |
| Double | Estreitamento; valores fora do intervalo são convertidos em Double.NegativeInfinity ou Double.PositiveInfinity. | Sim. Double suporta 17 dígitos decimais de precisão; Single suporta 9. |
| Int16 | Alargamento | Não |
| Int32 | Alargamento | Sim. Int32 suporta 10 dígitos decimais de precisão; Single suporta 9. |
| Int64 | Alargamento | Sim. Int64 suporta 19 dígitos decimais de precisão; Single suporta 9. |
| SByte | Alargamento | Não |
| UInt16 | Alargamento | Não |
| UInt32 | Alargamento | Sim. UInt32 suporta 10 dígitos decimais de precisão; Single suporta 9. |
| UInt64 | Alargamento | Sim. Int64 suporta 20 dígitos decimais de precisão; Single suporta 9. |
O exemplo a seguir converte o valor mínimo ou máximo de outros tipos numéricos primitivos em um valor 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)
Além disso, os valores DoubleDouble.NaN, Double.PositiveInfinitye Double.NegativeInfinity convertem em Single.NaN, Single.PositiveInfinitye Single.NegativeInfinity, respectivamente.
Observe que a conversão do valor de alguns tipos numéricos para um valor Single pode envolver uma perda de precisão. Como o exemplo ilustra, uma perda de precisão é possível ao converter Decimal, Double, Int32, Int64, UInt32e UInt64 valores em valores Single.
A conversão de um valor de Single em um Double é uma conversão crescente. A conversão pode resultar em uma perda de precisão se o tipo Double não tiver uma representação precisa para o valor Single.
A conversão de um valor Single para um valor de qualquer tipo de dados numéricos primitivos que não seja um Double é uma conversão de estreitamento e requer um operador cast (em C#) ou um método de conversão (em Visual Basic). Os valores que estão fora do intervalo do tipo de dados de destino, que são definidos pelas propriedades MinValue e MaxValue do tipo de destino, se comportam conforme mostrado na tabela a seguir.
| Tipo de alvo | Resultado |
|---|---|
| Qualquer tipo integral | Uma exceção OverflowException se a conversão ocorrer em um contexto verificado. Se a conversão ocorrer num contexto sem verificação (o padrão em C#), a operação de conversão é bem-sucedida, mas o valor excede. |
| Decimal | Uma OverflowException exceção. |
Além disso, Single.NaN, Single.PositiveInfinitye Single.NegativeInfinity lançam uma exceção OverflowException para conversões em inteiros em um contexto verificado, mas esses valores comportam-se de forma inesperada quando convertidos em inteiros em um contexto não verificado. Para conversões para Decimal, eles sempre lançam um OverflowException. Para conversões para Double, convertem-se em Double.NaN, Double.PositiveInfinitye Double.NegativeInfinity, respectivamente.
Observe que uma perda de precisão pode resultar da conversão de um valor Single para outro tipo numérico. No caso da conversão de valores de Single não integrais, como mostra a saída do exemplo, o componente fracionário é perdido quando o valor Single é arredondado (como no Visual Basic) ou truncado (como em C# e F#). Para conversões para valores Decimal, o valor Single pode não ter uma representação precisa no tipo de dados de destino.
O exemplo a seguir converte vários valores de Single em vários outros tipos numéricos. As conversões ocorrem num contexto verificado no Visual Basic (o padrão), em C# (por causa da palavra-chave checked) e em F# (por causa da declaração open Checked). A saída do exemplo mostra o resultado de conversões em um contexto verificado e não verificado. Você pode executar conversões em um contexto não verificado no Visual Basic compilando com a opção de compilador /removeintchecks+, em C# comentando a instrução checked e em F# comentando a instrução open Checked.
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 ∞ to Int64.
// Unable to convert ∞ to UInt64.
// Unable to convert ∞ to Decimal.
// ∞ (Single) --> ∞ (Double)
//
// Unable to convert -∞ to Int64.
// Unable to convert -∞ to UInt64.
// Unable to convert -∞ to Decimal.
// -∞ (Single) --> -∞ (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 ∞ to Int64.
// Unable to convert ∞ to UInt64.
// Unable to convert ∞ to Decimal.
// ∞ (Single) --> ∞ (Double)
//
// Unable to convert -∞ to Int64.
// Unable to convert -∞ to UInt64.
// Unable to convert -∞ to Decimal.
// -∞ (Single) --> -∞ (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 ∞ to Int64.
' Unable to convert ∞ to UInt64.
' Unable to convert ∞ to Decimal.
' ∞ (Single) --> ∞ (Double)
'
' Unable to convert -∞ to Int64.
' Unable to convert -∞ to UInt64.
' Unable to convert -∞ to Decimal.
' -∞ (Single) --> -∞ (Double)
Para obter mais informações sobre a conversão de tipos numéricos, consulte Conversão de Tipos no .NET e Tabelas de Conversão de Tipos.
Funcionalidade de ponto flutuante
A estrutura Single e os tipos relacionados fornecem métodos para executar as seguintes categorias de operações:
Comparação de valores. Você pode chamar o método Equals para determinar se dois valores Single são iguais ou o método CompareTo para determinar a relação entre dois valores.
A estrutura Single também suporta um conjunto completo de operadores de comparação. Por exemplo, você pode testar a igualdade ou a desigualdade ou determinar se um valor é maior ou igual a outro valor. Se um dos operandos for um Double, o valor Single será convertido em um Double antes de executar a comparação. Se um dos operandos for um tipo integral, ele será convertido em um Single antes de executar a comparação. Embora estas sejam conversões crescentes, podem envolver uma perda de precisão.
Advertência
Devido a diferenças na precisão, dois Single valores que você espera que sejam iguais podem acabar sendo desiguais, o que afeta o resultado da comparação. Consulte a secção sobre o Teste de igualdade para obter mais informações sobre como comparar dois valores Single.
Você também pode chamar os métodos IsNaN, IsInfinity, IsPositiveInfinitye IsNegativeInfinity para testar esses valores especiais.
Operações matemáticas. Operações aritméticas comuns, como adição, subtração, multiplicação e divisão, são implementadas por compiladores de linguagem e instruções de linguagem intermediária comum (CIL) em vez de por métodos Single. Se o outro operando em uma operação matemática é um Double, o Single é convertido em um Double antes de executar a operação, e o resultado da operação também é um valor Double. Se o outro operando for um tipo integral, ele será convertido em um Single antes de executar a operação, e o resultado da operação também será um valor Single.
Você pode executar outras operações matemáticas chamando
static(Sharedno Visual Basic) métodos na classe System.Math. Estes incluem métodos adicionais comumente usados para aritmética (como Math.Abs, Math.Signe Math.Sqrt), geometria (como Math.Cos e Math.Sin) e cálculo (como Math.Log). Em todos os casos, o valor Single é convertido em um Double.Você também pode manipular os bits individuais em um valor Single. O método BitConverter.GetBytes(Single) retorna seu padrão de bits em uma matriz de bytes. Ao passar essa matriz de bytes para o método BitConverter.ToInt32, você também pode preservar o padrão de bits do valor Single em um inteiro de 32 bits.
Arredondamento. O arredondamento é frequentemente usado como uma técnica para reduzir o impacto das diferenças entre valores causadas por problemas de representação e precisão de ponto flutuante. Você pode arredondar um valor Single chamando o método Math.Round. No entanto, observe que o valor Single é convertido em um Double antes do método ser chamado, e a conversão pode envolver uma perda de precisão.
Formatação. Você pode converter um valor de Single em sua representação de cadeia de caracteres chamando o método ToString ou usando o recurso de formatação composta . Para obter informações sobre como as cadeias de caracteres de formato controlam a representação de cadeias de caracteres de valores de vírgula flutuante, consulte Cadeias de caracteres de formato numérico padrão e Cadeias de caracteres de formato numérico personalizadas.
Analisar cadeias de caracteres. Você pode converter a representação de cadeia de caracteres de um valor de ponto flutuante em um valor Single chamando o método Parse ou TryParse. Se a operação de análise falhar, o método Parse lançará uma exceção, enquanto o método TryParse retornará
false.Conversão de tipo. A estrutura Single fornece uma implementação de interface explícita para a interface IConvertible, que suporta a conversão entre quaisquer dois tipos de dados .NET padrão. Os compiladores de linguagem também suportam a conversão implícita de valores para todos os outros tipos numéricos padrão, exceto para a conversão de Double em valores Single. A conversão de um valor de qualquer tipo numérico normalizado que não seja um Double para um Single é uma conversão alargada e não requer a utilização de um operador de fundição ou de um método de conversão.
No entanto, a conversão de valores inteiros de 32 bits e 64 bits pode envolver uma perda de precisão. A tabela a seguir lista as diferenças de precisão para os tipos de 32 bits, 64 bits e Double:
Tipo Precisão máxima (dígitos decimais) Precisão interna (dígitos decimais) Double 15 17 Int32 e UInt32 10 10 Int64 e UInt64 19 19 Single 7 9 O problema da precisão afeta com mais frequência os valores Single que são convertidos em valores Double. No exemplo a seguir, dois valores produzidos por operações de divisão idênticas são desiguais, porque um dos valores é um valor de ponto flutuante de precisão única que é convertido em um Double.
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 on .NET: // 0.3333333333333333 = 0.3333333432674408: Falselet 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 on .NET: // 0.3333333333333333 = 0.3333333432674408: FalseDim 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)) ' The example displays the following output: ' 0.3333333333333333 = 0.3333333432674408: False