System.Double yapısı
Bu makale, bu API'nin başvuru belgelerine ek açıklamalar sağlar.
Değer türü, Double negatif 1,79769313486232e308 ile pozitif 1,79769313486232e308 arasında değişen değerlerin yanı sıra pozitif veya negatif sıfır PositiveInfinity, , ve NegativeInfinitysayı (NaN) olmayan çift duyarlıklı 64 bitlik bir sayıyı temsil eder. Son derece büyük (gezegenler veya galaksiler arasındaki mesafeler gibi) veya son derece küçük (kilogram cinsinden bir maddenin moleküler kütlesi gibi) ve genellikle belirsiz olan (örneğin, dünyadan başka bir güneş sistemine olan uzaklık) değerleri temsil etmeye yöneliktir. Türü, Double ikili kayan nokta aritmetiği için IEC 60559:1989 (IEEE 754) standardına uygundur.
Kayan nokta gösterimi ve duyarlık
Veri türü, Double aşağıdaki tabloda gösterildiği gibi çift duyarlıklı kayan nokta değerlerini 64 bit ikili biçimde depolar:
Bölüm | Bits |
---|---|
İşaret veya mantis | 0-51 |
Üs | 52-62 |
İşaret (0 = Pozitif, 1 = Negatif) | 63 |
Ondalık kesirlerin bazı kesirli değerleri (1/3 veya Math.PIgibi) tam olarak temsil edemediği gibi, ikili kesirler de bazı kesirli değerleri temsil edemez. Örneğin, ondalık kesir olarak tam olarak .1 ile temsil edilen 1/10, .001100110011 ile ikili kesir olarak temsil edilir ve "0011" deseni sonsuza kadar yineleniyor. Bu durumda kayan nokta değeri, temsil ettiği sayının kesin bir gösterimini sağlar. Özgün kayan nokta değeri üzerinde ek matematiksel işlemler gerçekleştirmek genellikle duyarlık eksikliğini artırma eğilimindedir. Örneğin, .1 değerinin 10 ile çarpılması ve .1 değerinin dokuz kez eklenmesinin sonucunu karşılaştırırsak, sekiz işlem daha içerdiğinden bu toplamanın daha az kesin sonuç ürettiğini görürüz. Bu eşitsizliğin, yalnızca "R" standart sayısal biçim dizesini kullanarak iki Double değeri görüntülememiz durumunda görünür olduğunu ve gerekirse türün Double desteklediği 17 duyarlık basamaklarının tümünü görüntülediğini unutmayın.
using System;
public class Example13
{
public static void Main()
{
Double value = .1;
Double result1 = value * 10;
Double result2 = 0;
for (int ctr = 1; ctr <= 10; ctr++)
result2 += value;
Console.WriteLine(".1 * 10: {0:R}", result1);
Console.WriteLine(".1 Added 10 times: {0:R}", result2);
}
}
// The example displays the following output:
// .1 * 10: 1
// .1 Added 10 times: 0.99999999999999989
let value = 0.1
let result1 = value * 10.
let mutable result2 = 0.
for i = 1 to 10 do
result2 <- result2 + value
printfn $".1 * 10: {result1:R}"
printfn $".1 Added 10 times: {result2:R}"
// The example displays the following output:
// .1 * 10: 1
// .1 Added 10 times: 0.99999999999999989
Module Example14
Public Sub Main()
Dim value As Double = 0.1
Dim result1 As Double = value * 10
Dim result2 As Double
For ctr As Integer = 1 To 10
result2 += value
Next
Console.WriteLine(".1 * 10: {0:R}", result1)
Console.WriteLine(".1 Added 10 times: {0:R}", result2)
End Sub
End Module
' The example displays the following output:
' .1 * 10: 1
' .1 Added 10 times: 0.99999999999999989
Bazı sayılar tam olarak kesirli ikili değerler olarak temsil edilemediği için kayan noktalı sayılar yalnızca gerçek sayılara yakın olabilir.
Tüm kayan noktalı sayılar da sınırlı sayıda anlamlı basamağı vardır ve bu da kayan nokta değerinin gerçek bir sayıya ne kadar doğru yakın olduğunu belirler. Bir Double değerin en fazla 15 ondalık basamak duyarlık vardır, ancak dahili olarak en fazla 17 basamak tutulur. Bu, bazı kayan nokta işlemlerinin kayan nokta değerini değiştirme duyarlığından yoksun olabileceği anlamına gelir. Aşağıdaki örnek, bir gösterim sağlar. Çok büyük bir kayan nokta değeri tanımlar ve ardından ürününe Double.Epsilon ve bir katrilyon ekler. Ancak ürün, özgün kayan nokta değerini değiştiremeyecek kadar küçük. En az önemli rakamı binde bir, üründeki en önemli rakam ise 10-309 arasıdır.
using System;
public class Example14
{
public static void Main()
{
Double value = 123456789012.34567;
Double additional = Double.Epsilon * 1e15;
Console.WriteLine("{0} + {1} = {2}", value, additional,
value + additional);
}
}
// The example displays the following output:
// 123456789012.346 + 4.94065645841247E-309 = 123456789012.346
open System
let value = 123456789012.34567
let additional = Double.Epsilon * 1e15
printfn $"{value} + {additional} = {value + additional}"
// The example displays the following output:
// 123456789012.346 + 4.94065645841247E-309 = 123456789012.346
Module Example15
Public Sub Main()
Dim value As Double = 123456789012.34567
Dim additional As Double = Double.Epsilon * 1.0E+15
Console.WriteLine("{0} + {1} = {2}", value, additional,
value + additional)
End Sub
End Module
' The example displays the following output:
' 123456789012.346 + 4.94065645841247E-309 = 123456789012.346
Kayan noktalı bir sayının sınırlı duyarlığı çeşitli sonuçlara neden olur:
Belirli bir duyarlık için eşit görünen iki kayan noktalı sayı, en az önemli basamakları farklı olduğundan eşit olarak karşılaştırılamayabilir. Aşağıdaki örnekte, bir dizi sayı bir araya eklenir ve bunların toplamı beklenen toplamlarıyla karşılaştırılır. İki değer aynı gibi görünse de, yöntemine yapılan
Equals
bir çağrı bunların olmadığını gösterir.using System; public class Example10 { public static void Main() { Double[] values = { 10.0, 2.88, 2.88, 2.88, 9.0 }; Double result = 27.64; Double total = 0; 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 ({0}) does not equal the total ({1}).", total, result); } } // The example displays the following output: // The sum of the values (36.64) does not equal the total (36.64). // // 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).
let values = [ 10.0; 2.88; 2.88; 2.88; 9.0 ] let result = 27.64 let total = List.sum values 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 (36.64) does not equal the total (36.64). // // 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).
Module Example11 Public Sub Main() Dim values() As Double = {10.0, 2.88, 2.88, 2.88, 9.0} Dim result As Double = 27.64 Dim total As Double 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 (36.64) does not equal the total (36.64). ' ' 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).
İki değerin Console.WriteLine(String, Object, Object) tüm önemli basamaklarını Double görüntülemek için
{0:R}
{1:R}
ve{1}
içindeki biçim{0}
öğelerini değiştirirseniz, toplama işlemleri sırasında duyarlık kaybı nedeniyle iki değerin eşit olmadığı açıktır. Bu durumda, karşılaştırmayı gerçekleştirmeden önce değerleri istenen duyarlık düzeyine yuvarlama Double yöntemini çağırarak Math.Round(Double, Int32) sorun çözülebilir.Kayan noktalı sayı kullanan bir matematik veya karşılaştırma işlemi, ondalık sayı kullanıldığında aynı sonucu vermeyebilir çünkü ikili kayan noktalı sayı ondalık sayıya eşit olmayabilir. Önceki bir örnek, .1 ile 10 çarpımının sonucunu görüntüleyip 0,1 kez ekleyerek bunu göstermiş.
Kesirli değerler içeren sayısal işlemlerde doğruluk önemliyse, türü yerine Double öğesini Decimal kullanabilirsiniz. veya türlerinin aralığını Int64 aşan tamsayı değerlerine sahip sayısal işlemlerde doğruluk önemliyse, türünü kullanınBigInteger.UInt64
Kayan noktalı bir sayı söz konusu olduğunda değer gidiş dönüş olmayabilir. Bir işlem özgün kayan noktalı sayıyı başka bir forma dönüştürürse, ters işlem dönüştürülen formu kayan noktalı sayıya geri dönüştürürse ve son kayan nokta sayısı özgün kayan nokta numarasına eşit değilse, değer gidiş dönüş olarak söylenir. Dönüşümde bir veya daha az önemli basamak kaybolduğundan veya değiştirildiğinden gidiş dönüş başarısız olabilir. Aşağıdaki örnekte, üç Double değer dizelere dönüştürülür ve bir dosyaya kaydedilir. Ancak çıktıda gösterildiği gibi, değerler aynı gibi görünse de, geri yüklenen değerler özgün değerlere eşit değildir.
using System; using System.IO; public class Example11 { public static void Main() { StreamWriter sw = new StreamWriter(@".\Doubles.dat"); Double[] values = { 2.2 / 1.01, 1.0 / 3, Math.PI }; for (int ctr = 0; ctr < values.Length; ctr++) { sw.Write(values[ctr].ToString()); if (ctr != values.Length - 1) sw.Write("|"); } sw.Close(); Double[] restoredValues = new Double[values.Length]; StreamReader sr = new StreamReader(@".\Doubles.dat"); string temp = sr.ReadToEnd(); string[] tempStrings = temp.Split('|'); for (int ctr = 0; ctr < tempStrings.Length; ctr++) restoredValues[ctr] = Double.Parse(tempStrings[ctr]); for (int ctr = 0; ctr < values.Length; ctr++) Console.WriteLine("{0} {2} {1}", values[ctr], restoredValues[ctr], values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>"); } } // The example displays the following output: // 2.17821782178218 <> 2.17821782178218 // 0.333333333333333 <> 0.333333333333333 // 3.14159265358979 <> 3.14159265358979
open System open System.IO let values = [ 2.2 / 1.01; 1. / 3.; Math.PI ] using (new StreamWriter(@".\Doubles.dat")) (fun sw -> for i = 0 to values.Length - 1 do sw.Write(string values[i]) if i <> values.Length - 1 then sw.Write "|") using (new StreamReader(@".\Doubles.dat")) (fun sr -> let temp = sr.ReadToEnd() let tempStrings = temp.Split '|' let restoredValues = [ for i = 0 to tempStrings.Length - 1 do Double.Parse tempStrings[i] ] 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.17821782178218 <> 2.17821782178218 // 0.333333333333333 <> 0.333333333333333 // 3.14159265358979 <> 3.14159265358979
Imports System.IO Module Example12 Public Sub Main() Dim sw As New StreamWriter(".\Doubles.dat") Dim values() As Double = {2.2 / 1.01, 1.0 / 3, 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 Double Dim sr As New StreamReader(".\Doubles.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) = Double.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.17821782178218 <> 2.17821782178218 ' 0.333333333333333 <> 0.333333333333333 ' 3.14159265358979 <> 3.14159265358979
Bu durumda, aşağıdaki örnekte gösterildiği gibi değerlerin tam duyarlığı Double korunabilmesi için "G17" standart sayısal biçim dizesi kullanılarak değerler başarıyla yuvarlanabilir.
using System; using System.IO; public class Example12 { public static void Main() { StreamWriter sw = new StreamWriter(@".\Doubles.dat"); Double[] values = { 2.2 / 1.01, 1.0 / 3, Math.PI }; for (int ctr = 0; ctr < values.Length; ctr++) sw.Write("{0:G17}{1}", values[ctr], ctr < values.Length - 1 ? "|" : ""); sw.Close(); Double[] restoredValues = new Double[values.Length]; StreamReader sr = new StreamReader(@".\Doubles.dat"); string temp = sr.ReadToEnd(); string[] tempStrings = temp.Split('|'); for (int ctr = 0; ctr < tempStrings.Length; ctr++) restoredValues[ctr] = Double.Parse(tempStrings[ctr]); for (int ctr = 0; ctr < values.Length; ctr++) Console.WriteLine("{0} {2} {1}", values[ctr], restoredValues[ctr], values[ctr].Equals(restoredValues[ctr]) ? "=" : "<>"); } } // The example displays the following output: // 2.17821782178218 = 2.17821782178218 // 0.333333333333333 = 0.333333333333333 // 3.14159265358979 = 3.14159265358979
open System open System.IO let values = [ 2.2 / 1.01; 1. / 3.; Math.PI ] using (new StreamWriter(@".\Doubles.dat")) (fun sw -> for i = 0 to values.Length - 1 do sw.Write $"""{values[i]:G17}{if i < values.Length - 1 then "|" else ""}""") using (new StreamReader(@".\Doubles.dat")) (fun sr -> let temp = sr.ReadToEnd() let tempStrings = temp.Split '|' let restoredValues = [ for i = 0 to tempStrings.Length - 1 do Double.Parse tempStrings[i] ] for i = 0 to values.Length - 1 do printfn $"""{restoredValues[i]} {if values[i].Equals restoredValues[i] then "=" else "<>"} {values[i]}""") // The example displays the following output: // 2.17821782178218 = 2.17821782178218 // 0.333333333333333 = 0.333333333333333 // 3.14159265358979 = 3.14159265358979
Imports System.IO Module Example13 Public Sub Main() Dim sw As New StreamWriter(".\Doubles.dat") Dim values() As Double = {2.2 / 1.01, 1.0 / 3, Math.PI} For ctr As Integer = 0 To values.Length - 1 sw.Write("{0:G17}{1}", values(ctr), If(ctr < values.Length - 1, "|", "")) Next sw.Close() Dim restoredValues(values.Length - 1) As Double Dim sr As New StreamReader(".\Doubles.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) = Double.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.17821782178218 = 2.17821782178218 ' 0.333333333333333 = 0.333333333333333 ' 3.14159265358979 = 3.14159265358979
Single değerlerin duyarlığı değerlerden daha Double azdır. Single Eşit gibi Double görünen bir değere dönüştürülen bir değer, duyarlık farklılıkları nedeniyle genellikle değere eşit Double değildir. Aşağıdaki örnekte, aynı bölme işlemlerinin sonucu bir Double ve Single değerine atanır. Single değeri bir Doubledeğerine atandıktan sonra, iki değerin karşılaştırması bunların eşit olmadığını gösterir.
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("{0:R} = {1:R}: {2}", value1, value2, 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
Bu sorunu önlemek için veri türünün yerine öğesini kullanın Double veya her iki değerin Single de aynı duyarlıkta sahip olması için yöntemini kullanın Round .
Buna ek olarak, aritmetik ve değerlerle Double atama işlemlerinin sonucu, türün duyarlık kaybı nedeniyle platforma Double göre biraz farklılık gösterebilir. Örneğin, değişmez Double değer atamanın sonucu.NET'in 32 bit ve 64 bit sürümlerinde farklılık gösterebilir. Aşağıdaki örnekte, -4,42330604244772E-305 değişmez değeri ve değeri -4,42330604244772E-305 olan bir Double değişken atandığında bu fark gösterilmektedir. Bu durumda yöntemin sonucunun Parse(String) duyarlık kaybı yaşamadığını unutmayın.
double value = -4.42330604244772E-305;
double fromLiteral = -4.42330604244772E-305;
double fromVariable = value;
double fromParse = Double.Parse("-4.42330604244772E-305");
Console.WriteLine("Double value from literal: {0,29:R}", fromLiteral);
Console.WriteLine("Double value from variable: {0,28:R}", fromVariable);
Console.WriteLine("Double value from Parse method: {0,24:R}", fromParse);
// On 32-bit versions of the .NET Framework, the output is:
// Double value from literal: -4.42330604244772E-305
// Double value from variable: -4.42330604244772E-305
// Double value from Parse method: -4.42330604244772E-305
//
// On other versions of the .NET Framework, the output is:
// Double value from literal: -4.4233060424477198E-305
// Double value from variable: -4.4233060424477198E-305
// Double value from Parse method: -4.42330604244772E-305
let value = -4.42330604244772E-305
let fromLiteral = -4.42330604244772E-305
let fromVariable = value
let fromParse = Double.Parse "-4.42330604244772E-305"
printfn $"Double value from literal: {fromLiteral,29:R}"
printfn $"Double value from variable: {fromVariable,28:R}"
printfn $"Double value from Parse method: {fromParse,24:R}"
// On 32-bit versions of the .NET Framework, the output is:
// Double value from literal: -4.42330604244772E-305
// Double value from variable: -4.42330604244772E-305
// Double value from Parse method: -4.42330604244772E-305
//
// On other versions of the .NET Framework, the output is:
// Double value from literal: -4.4233060424477198E-305
// Double value from variable: -4.4233060424477198E-305
// Double value from Parse method: -4.42330604244772E-305
Dim value As Double = -4.4233060424477198E-305
Dim fromLiteral As Double = -4.4233060424477198E-305
Dim fromVariable As Double = value
Dim fromParse As Double = Double.Parse("-4.42330604244772E-305")
Console.WriteLine("Double value from literal: {0,29:R}", fromLiteral)
Console.WriteLine("Double value from variable: {0,28:R}", fromVariable)
Console.WriteLine("Double value from Parse method: {0,24:R}", fromParse)
' On 32-bit versions of the .NET Framework, the output is:
' Double value from literal: -4.42330604244772E-305
' Double value from variable: -4.42330604244772E-305
' Double value from Parse method: -4.42330604244772E-305
'
' On other versions of the .NET Framework, the output is:
' Double value from literal: -4.4233060424477198E-305
' Double value from variable: -4.4233060424477198E-305
' Double value from Parse method: -4.42330604244772E-305
Eşitlik testi
Eşit olarak kabul edilmesi için iki Double değerin aynı değerleri temsil etmesi gerekir. Ancak, değerler arasındaki duyarlık farklılıkları nedeniyle veya bir veya her iki değere göre duyarlık kaybı nedeniyle, özdeş olması beklenen kayan nokta değerleri genellikle en az önemli basamaklarındaki farklılıklar nedeniyle eşit değildir. Sonuç olarak, iki değerin Equals eşit olup olmadığını belirlemek için yöntemine CompareTo çağrılar veya iki Double değer arasındaki ilişkiyi belirlemek için yöntemine çağrılar, genellikle beklenmeyen sonuçlar verir. Bu, aşağıdaki örnekte, ilkinde 15 basamak duyarlık, ikincisinde ise 17 basamak bulunduğu için eşit olmayan iki eşit Double değer olduğu görülmektedir.
using System;
public class Example
{
public static void Main()
{
double value1 = .333333333333333;
double value2 = 1.0/3;
Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2));
}
}
// The example displays the following output:
// 0.333333333333333 = 0.33333333333333331: False
open System
let value1 = 0.333333333333333
let value2 = 1. / 3.
printfn $"{value1:R} = {value2:R}: {value1.Equals value2}"
// The example displays the following output:
// 0.333333333333333 = 0.33333333333333331: False
Module Example1
Public Sub Main()
Dim value1 As Double = 0.333333333333333
Dim value2 As Double = 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.333333333333333 = 0.33333333333333331: False
Farklı kod yollarını izleyen ve farklı şekillerde işlenen hesaplanan değerlerin genellikle eşit olmadığını kanıtlar. Aşağıdaki örnekte bir Double değerin karesi alınır ve ardından özgün değeri geri yüklemek için karekök hesaplanır. Bir saniye Double 3,51 ile çarpılır ve sonucun karekökünün özgün değeri geri yüklemek için 3,51'e bölünmesi gerekir. İki değer aynı gibi görünse de, yöntemine yapılan Equals(Double) bir çağrı bunların eşit olmadığını gösterir. Her Double değerinin tüm önemli basamaklarını görüntüleyen bir sonuç dizesi döndürmek için "R" standart biçim dizesini kullanmak, ikinci değerin birinciden .0000000000001 daha küçük olduğunu gösterir.
using System;
public class Example1
{
public static void Main()
{
double value1 = 100.10142;
value1 = Math.Sqrt(Math.Pow(value1, 2));
double value2 = Math.Pow(value1 * 3.51, 2);
value2 = Math.Sqrt(value2) / 3.51;
Console.WriteLine("{0} = {1}: {2}\n",
value1, value2, value1.Equals(value2));
Console.WriteLine("{0:R} = {1:R}", value1, value2);
}
}
// The example displays the following output:
// 100.10142 = 100.10142: False
//
// 100.10142 = 100.10141999999999
open System
let value1 =
Math.Pow(100.10142, 2)
|> sqrt
let value2 =
let v = pown (value1 * 3.51) 2
(Math.Sqrt v) / 3.51
printfn $"{value1} = {value2}: {value1.Equals value2}\n"
printfn $"{value1:R} = {value2:R}"
// The example displays the following output:
// 100.10142 = 100.10142: False
//
// 100.10142 = 100.10141999999999
Module Example2
Public Sub Main()
Dim value1 As Double = 100.10142
value1 = Math.Sqrt(Math.Pow(value1, 2))
Dim value2 As Double = Math.Pow(value1 * 3.51, 2)
value2 = Math.Sqrt(value2) / 3.51
Console.WriteLine("{0} = {1}: {2}",
value1, value2, value1.Equals(value2))
Console.WriteLine()
Console.WriteLine("{0:R} = {1:R}", value1, value2)
End Sub
End Module
' The example displays the following output:
' 100.10142 = 100.10142: False
'
' 100.10142 = 100.10141999999999
Bir duyarlık kaybının karşılaştırmanın sonucunu etkileyeceği durumlarda, veya CompareTo yöntemini çağırmak Equals için aşağıdaki alternatiflerden herhangi birini benimseyebilirsiniz:
Her iki değerin Math.Round de aynı duyarlıkta sahip olduğundan emin olmak için yöntemini çağırın. Aşağıdaki örnek, önceki bir örneği bu yaklaşımı kullanacak şekilde değiştirerek iki kesirli değerin eşdeğer olmasını sağlar.
using System; public class Example2 { public static void Main() { double value1 = .333333333333333; double value2 = 1.0 / 3; int precision = 7; value1 = Math.Round(value1, precision); value2 = Math.Round(value2, precision); Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2)); } } // The example displays the following output: // 0.3333333 = 0.3333333: True
open System let v1 = 0.333333333333333 let v2 = 1. / 3. let precision = 7 let value1 = Math.Round(v1, precision) let value2 = Math.Round(v2, precision) 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 Double = 0.333333333333333 Dim value2 As Double = 1 / 3 Dim precision As Integer = 7 value1 = Math.Round(value1, precision) value2 = 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
Duyarlık sorunu orta nokta değerlerini yuvarlama için de geçerlidir. Daha fazla bilgi için yöntemine Math.Round(Double, Int32, MidpointRounding) bakın.
Eşitlik yerine yaklaşık eşitlik testi. Bu, iki değerin farklı ancak yine de eşit olabileceği mutlak bir tutar tanımlamanızı veya daha küçük değerin daha büyük değerden ayrışabileceği göreli bir miktar tanımlamanızı gerektirir.
Uyarı
Double.Epsilon bazen eşitlik testi sırasında iki Double değer arasındaki uzaklığın mutlak ölçüsü olarak kullanılır. Ancak, Double.Epsilon değeri sıfır olan bir Double öğesine eklenebilecek veya çıkarılabilecek en küçük olası değeri ölçer. Çoğu pozitif ve negatif Double değer için değeri Double.Epsilon algılanamaz kadar küçüktür. Bu nedenle, sıfır olan değerler dışında, eşitlik için testlerde kullanılmasını önermeyiz.
Aşağıdaki örnek, iki değer arasındaki göreli farkı test eden bir
IsApproximatelyEqual
yöntem tanımlamak için ikinci yaklaşımı kullanır. Ayrıca yöntemine ve yöntemine yapılan çağrılarınIsApproximatelyEqual
sonucunu da karşıttır Equals(Double) .using System; public class Example3 { public static void Main() { double one1 = .1 * 10; double one2 = 0; for (int ctr = 1; ctr <= 10; ctr++) one2 += .1; 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, .000000001)); } static bool IsApproximatelyEqual(double value1, double value2, double 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 = 0.99999999999999989: False // 1 is approximately equal to 0.99999999999999989: True
open System let isApproximatelyEqual (value1: double) (value2: double) (epsilon: double) = // If they are equal anyway, just return True. if value1.Equals value2 then true else // Handle NaN, Infinity. if Double.IsInfinity value1 || Double.IsNaN value1 then value1.Equals value2 elif Double.IsInfinity value2 || Double.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.1 * 10. let mutable one2 = 0. for _ = 1 to 10 do one2 <- one2 + 0.1 printfn $"{one1:R} = {one2:R}: {one1.Equals one2}" printfn $"{one1:R} is approximately equal to {one2:R}: {isApproximatelyEqual one1 one2 0.000000001}" // The example displays the following output: // 1 = 0.99999999999999989: False // 1 is approximately equal to 0.99999999999999989: True
Module Example4 Public Sub Main() Dim one1 As Double = 0.1 * 10 Dim one2 As Double = 0 For ctr As Integer = 1 To 10 one2 += 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.000000001)) End Sub Function IsApproximatelyEqual(value1 As Double, value2 As Double, epsilon As Double) As Boolean ' If they are equal anyway, just return True. If value1.Equals(value2) Then Return True ' Handle NaN, Infinity. If Double.IsInfinity(value1) Or Double.IsNaN(value1) Then Return value1.Equals(value2) ElseIf Double.IsInfinity(value2) Or Double.IsNaN(value2) Then Return value1.Equals(value2) End If ' Handle zero to avoid division by zero Dim divisor As Double = 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 = 0.99999999999999989: False ' 1 is approximately equal to 0.99999999999999989: True
Kayan nokta değerleri ve özel durumlar
Taşma veya sıfıra bölme gibi geçersiz işlemlerde özel durumlar oluşturan integral türlerine sahip işlemlerden farklı olarak, kayan nokta değerlerine sahip işlemler özel durumlar oluşturmaz. Bunun yerine, olağanüstü durumlarda kayan nokta işleminin sonucu sıfır, pozitif sonsuz, negatif sonsuzdur veya sayı değildir (NaN):
Kayan nokta işleminin sonucu hedef biçim için çok küçükse, sonuç sıfır olur. Aşağıdaki örnekte gösterildiği gibi, çok küçük iki sayı çarpıldığında bu durum oluşabilir.
using System; public class Example6 { public static void Main() { Double value1 = 1.1632875981534209e-225; Double value2 = 9.1642346778e-175; Double result = value1 * value2; Console.WriteLine("{0} * {1} = {2}", value1, value2, result); Console.WriteLine("{0} = 0: {1}", result, result.Equals(0.0)); } } // The example displays the following output: // 1.16328759815342E-225 * 9.1642346778E-175 = 0 // 0 = 0: True
let value1 = 1.1632875981534209e-225 let value2 = 9.1642346778e-175 let result = value1 * value2 printfn $"{value1} * {value2} = {result}" printfn $"{result} = 0: {result.Equals 0.0}" // The example displays the following output: // 1.16328759815342E-225 * 9.1642346778E-175 = 0 // 0 = 0: True
Module Example7 Public Sub Main() Dim value1 As Double = 1.1632875981534209E-225 Dim value2 As Double = 9.1642346778E-175 Dim result As Double = value1 * value2 Console.WriteLine("{0} * {1} = {2}", value1, value2, result) Console.WriteLine("{0} = 0: {1}", result, result.Equals(0.0)) End Sub End Module ' The example displays the following output: ' 1.16328759815342E-225 * 9.1642346778E-175 = 0 ' 0 = 0: True
Kayan nokta işleminin sonucunun büyüklüğü hedef biçimin aralığını aşarsa, işlemin PositiveInfinity sonucu sonucun işaretine uygun olarak veya NegativeInfinityolur. Taşan Double.MaxValue bir işlemin sonucu , PositiveInfinitytaşan Double.MinValue bir işlemin sonucu ise aşağıdaki örnekte gösterildiği gibi şeklindedir NegativeInfinity.
using System; public class Example7 { public static void Main() { Double value1 = 4.565e153; Double value2 = 6.9375e172; Double result = value1 * value2; Console.WriteLine("PositiveInfinity: {0}", Double.IsPositiveInfinity(result)); Console.WriteLine("NegativeInfinity: {0}\n", Double.IsNegativeInfinity(result)); value1 = -value1; result = value1 * value2; Console.WriteLine("PositiveInfinity: {0}", Double.IsPositiveInfinity(result)); Console.WriteLine("NegativeInfinity: {0}", Double.IsNegativeInfinity(result)); } } // The example displays the following output: // PositiveInfinity: True // NegativeInfinity: False // // PositiveInfinity: False // NegativeInfinity: True
open System let value1 = 4.565e153 let value2 = 6.9375e172 let result = value1 * value2 printfn $"PositiveInfinity: {Double.IsPositiveInfinity result}" printfn $"NegativeInfinity: {Double.IsNegativeInfinity result}\n" let value3 = - value1 let result2 = value2 * value3 printfn $"PositiveInfinity: {Double.IsPositiveInfinity result2}" printfn $"NegativeInfinity: {Double.IsNegativeInfinity result2}" // The example displays the following output: // PositiveInfinity: True // NegativeInfinity: False // // PositiveInfinity: False // NegativeInfinity: True
Module Example8 Public Sub Main() Dim value1 As Double = 4.565E+153 Dim value2 As Double = 6.9375E+172 Dim result As Double = value1 * value2 Console.WriteLine("PositiveInfinity: {0}", Double.IsPositiveInfinity(result)) Console.WriteLine("NegativeInfinity: {0}", Double.IsNegativeInfinity(result)) Console.WriteLine() value1 = -value1 result = value1 * value2 Console.WriteLine("PositiveInfinity: {0}", Double.IsPositiveInfinity(result)) Console.WriteLine("NegativeInfinity: {0}", Double.IsNegativeInfinity(result)) End Sub End Module ' The example displays the following output: ' PositiveInfinity: True ' NegativeInfinity: False ' ' PositiveInfinity: False ' NegativeInfinity: True
PositiveInfinity ayrıca pozitif bir kar payı ile sıfıra bölmeden ve NegativeInfinity negatif bir kar payı ile sıfıra bölmeden elde edilen sonuçlar.
Kayan nokta işlemi geçersizse, işlemin sonucu olur NaN. Örneğin, NaN aşağıdaki işlemlerden elde edilen sonuçlar:
Sıfıra bölme ve sıfıra bölme. Sıfıra bölmenin diğer durumlarının veya NegativeInfinityile PositiveInfinity sonuçlandığını unutmayın.
Geçersiz giriş içeren herhangi bir kayan nokta işlemi. Örneğin, yöntemini negatif bir değerle çağırmakMath.Sqrt, yöntemini negatif değerden büyük veya daha az olan bir değerle çağırmak Math.Acos gibi döndürürNaN.
değeri Double.NaNolan bağımsız değişken içeren herhangi bir işlem.
Tür dönüştürmeleri
Yapı Double açık veya örtük dönüştürme işleçleri tanımlamaz; bunun yerine, dönüştürmeler derleyici tarafından uygulanır.
Herhangi bir ilkel sayısal türün değerinin bir'e Double dönüştürülmesi bir genişletme dönüştürmesidir ve bu nedenle bir derleyici açıkça gerektirmediği sürece açık bir atama işleci veya dönüştürme yöntemi çağrısı gerektirmez. Örneğin, C# derleyicisi için dönüştürmeler DecimalDoubleiçin bir atama işleci gerekirken, Visual Basic derleyicisi bunu yapmaz. Aşağıdaki örnek, diğer ilkel sayısal türlerin en düşük veya en yüksek değerini değerine Doubledönüştürür.
using System;
public class Example4
{
public static void Main()
{
dynamic[] values = { Byte.MinValue, Byte.MaxValue, Decimal.MinValue,
Decimal.MaxValue, Int16.MinValue, Int16.MaxValue,
Int32.MinValue, Int32.MaxValue, Int64.MinValue,
Int64.MaxValue, SByte.MinValue, SByte.MaxValue,
Single.MinValue, Single.MaxValue, UInt16.MinValue,
UInt16.MaxValue, UInt32.MinValue, UInt32.MaxValue,
UInt64.MinValue, UInt64.MaxValue };
double dblValue;
foreach (var value in values)
{
if (value.GetType() == typeof(Decimal))
dblValue = (Double)value;
else
dblValue = value;
Console.WriteLine("{0} ({1}) --> {2:R} ({3})",
value, value.GetType().Name,
dblValue, dblValue.GetType().Name);
}
}
}
// The example displays the following output:
// 0 (Byte) --> 0 (Double)
// 255 (Byte) --> 255 (Double)
// -79228162514264337593543950335 (Decimal) --> -7.9228162514264338E+28 (Double)
// 79228162514264337593543950335 (Decimal) --> 7.9228162514264338E+28 (Double)
// -32768 (Int16) --> -32768 (Double)
// 32767 (Int16) --> 32767 (Double)
// -2147483648 (Int32) --> -2147483648 (Double)
// 2147483647 (Int32) --> 2147483647 (Double)
// -9223372036854775808 (Int64) --> -9.2233720368547758E+18 (Double)
// 9223372036854775807 (Int64) --> 9.2233720368547758E+18 (Double)
// -128 (SByte) --> -128 (Double)
// 127 (SByte) --> 127 (Double)
// -3.402823E+38 (Single) --> -3.4028234663852886E+38 (Double)
// 3.402823E+38 (Single) --> 3.4028234663852886E+38 (Double)
// 0 (UInt16) --> 0 (Double)
// 65535 (UInt16) --> 65535 (Double)
// 0 (UInt32) --> 0 (Double)
// 4294967295 (UInt32) --> 4294967295 (Double)
// 0 (UInt64) --> 0 (Double)
// 18446744073709551615 (UInt64) --> 1.8446744073709552E+19 (Double)
open System
let values: obj[] =
[| Byte.MinValue; Byte.MaxValue; Decimal.MinValue
Decimal.MaxValue; Int16.MinValue; Int16.MaxValue
Int32.MinValue; Int32.MaxValue; Int64.MinValue
Int64.MaxValue; SByte.MinValue; SByte.MaxValue
Single.MinValue; Single.MaxValue; UInt16.MinValue
UInt16.MaxValue; UInt32.MinValue, UInt32.MaxValue
UInt64.MinValue; UInt64.MaxValue |]
for value in values do
let dblValue = value :?> double
printfn $"{value} ({value.GetType().Name}) --> {dblValue:R} ({dblValue.GetType().Name})"
// The example displays the following output:
// 0 (Byte) --> 0 (Double)
// 255 (Byte) --> 255 (Double)
// -79228162514264337593543950335 (Decimal) --> -7.9228162514264338E+28 (Double)
// 79228162514264337593543950335 (Decimal) --> 7.9228162514264338E+28 (Double)
// -32768 (Int16) --> -32768 (Double)
// 32767 (Int16) --> 32767 (Double)
// -2147483648 (Int32) --> -2147483648 (Double)
// 2147483647 (Int32) --> 2147483647 (Double)
// -9223372036854775808 (Int64) --> -9.2233720368547758E+18 (Double)
// 9223372036854775807 (Int64) --> 9.2233720368547758E+18 (Double)
// -128 (SByte) --> -128 (Double)
// 127 (SByte) --> 127 (Double)
// -3.402823E+38 (Single) --> -3.4028234663852886E+38 (Double)
// 3.402823E+38 (Single) --> 3.4028234663852886E+38 (Double)
// 0 (UInt16) --> 0 (Double)
// 65535 (UInt16) --> 65535 (Double)
// 0 (UInt32) --> 0 (Double)
// 4294967295 (UInt32) --> 4294967295 (Double)
// 0 (UInt64) --> 0 (Double)
// 18446744073709551615 (UInt64) --> 1.8446744073709552E+19 (Double)
Module Example5
Public Sub Main()
Dim values() As Object = {Byte.MinValue, Byte.MaxValue, Decimal.MinValue,
Decimal.MaxValue, Int16.MinValue, Int16.MaxValue,
Int32.MinValue, Int32.MaxValue, Int64.MinValue,
Int64.MaxValue, SByte.MinValue, SByte.MaxValue,
Single.MinValue, Single.MaxValue, UInt16.MinValue,
UInt16.MaxValue, UInt32.MinValue, UInt32.MaxValue,
UInt64.MinValue, UInt64.MaxValue}
Dim dblValue As Double
For Each value In values
dblValue = value
Console.WriteLine("{0} ({1}) --> {2:R} ({3})",
value, value.GetType().Name,
dblValue, dblValue.GetType().Name)
Next
End Sub
End Module
' The example displays the following output:
' 0 (Byte) --> 0 (Double)
' 255 (Byte) --> 255 (Double)
' -79228162514264337593543950335 (Decimal) --> -7.9228162514264338E+28 (Double)
' 79228162514264337593543950335 (Decimal) --> 7.9228162514264338E+28 (Double)
' -32768 (Int16) --> -32768 (Double)
' 32767 (Int16) --> 32767 (Double)
' -2147483648 (Int32) --> -2147483648 (Double)
' 2147483647 (Int32) --> 2147483647 (Double)
' -9223372036854775808 (Int64) --> -9.2233720368547758E+18 (Double)
' 9223372036854775807 (Int64) --> 9.2233720368547758E+18 (Double)
' -128 (SByte) --> -128 (Double)
' 127 (SByte) --> 127 (Double)
' -3.402823E+38 (Single) --> -3.4028234663852886E+38 (Double)
' 3.402823E+38 (Single) --> 3.4028234663852886E+38 (Double)
' 0 (UInt16) --> 0 (Double)
' 65535 (UInt16) --> 65535 (Double)
' 0 (UInt32) --> 0 (Double)
' 4294967295 (UInt32) --> 4294967295 (Double)
' 0 (UInt64) --> 0 (Double)
' 18446744073709551615 (UInt64) --> 1.8446744073709552E+19 (Double)
Buna ek olarak, Single , ve Single.NegativeInfinity değerleri Single.PositiveInfinitySingle.NaNsırasıyla , Double.PositiveInfinityve Double.NegativeInfinityolarak dönüştürülürDouble.NaN.
Bazı sayısal türlerin değerini bir değere Double dönüştürme işleminin duyarlık kaybı içerebileceğini unutmayın. Örnekte gösterildiği gibi, , Int64ve UInt64 değerleri değerlere Double dönüştürülürken Decimalduyarlık kaybı mümkündür.
Bir Double değerin başka bir ilkel sayısal veri türündeki bir değere dönüştürülmesi bir daraltma dönüştürme işlemidir ve bir dönüştürme işleci (C#'de), dönüştürme yöntemi (Visual Basic'te) veya bir Convert yöntem çağrısı gerektirir. Hedef türün ve MaxValue
özellikleri tarafından tanımlanan hedef veri türü aralığının MinValue
dışında olan değerler, aşağıdaki tabloda gösterildiği gibi davranır.
Hedef türü | Result |
---|---|
Herhangi bir tam sayı türü | OverflowException Dönüştürmenin denetlenen bir bağlamda gerçekleşmesi durumunda bir özel durum. Dönüştürme işaretlenmemiş bir bağlamda gerçekleşirse (C# dilinde varsayılan değer), dönüştürme işlemi başarılı olur ancak değer taşıyor. |
Decimal | Bir OverflowException özel durum. |
Single | Single.NegativeInfinity negatif değerler için. Single.PositiveInfinity pozitif değerler için. |
Buna ek olarak, Double.NaN, Double.PositiveInfinityve Double.NegativeInfinity işaretli bir bağlamda tamsayılara dönüştürmeler için bir oluşturur OverflowException , ancak bu değerler işaretsiz bir bağlamda tamsayılara dönüştürüldüğünde taşıyor. dönüştürmeleri Decimaliçin her zaman bir OverflowExceptionoluşturur. dönüştürmeleri Singleiçin sırasıyla , Single.PositiveInfinityve Single.NegativeInfinityolarak dönüştürülürSingle.NaN.
Duyarlık kaybı, bir değerin başka bir Double sayısal türe dönüştürülmesiyle sonuçlanabilir. Tamsayı türlerinden herhangi birine dönüştürme durumunda, örnekte gösterildiği gibi, değer yuvarlandığında Double (Visual Basic'te olduğu gibi) veya kesildiğinde (C# dilinde olduğu gibi) kesirli bileşen kaybolur. ve Single değerlerine Decimal dönüştürmeler için, değerin Double hedef veri türünde kesin bir gösterimi olmayabilir.
Aşağıdaki örnek, bir dizi Double değeri diğer birkaç sayısal türe dönüştürür. Dönüştürmeler Visual Basic'te (varsayılan), C# dilinde (işaretli anahtar sözcük nedeniyle) ve F# dilinde (İşaretli modül nedeniyle) denetlenen bir bağlamda gerçekleşir. Örnekten elde edilen çıktı, işaretlenmemiş bir bağlamın her ikisinde de dönüştürmelerin sonucunu gösterir. Visual Basic'te derleyici anahtarıyla /removeintchecks+
derleyerek, C# dilinde deyimini açıklama satırı yaparak ve F# dilinde deyimini açıklama satırı yaparak denetlenmeyen checked
open Checked
bir bağlamda dönüştürme gerçekleştirebilirsiniz.
using System;
public class Example5
{
public static void Main()
{
Double[] values = { Double.MinValue, -67890.1234, -12345.6789,
12345.6789, 67890.1234, Double.MaxValue,
Double.NaN, Double.PositiveInfinity,
Double.NegativeInfinity };
checked
{
foreach (var value in values)
{
try
{
Int64 lValue = (long)value;
Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
value, value.GetType().Name,
lValue, lValue.GetType().Name);
}
catch (OverflowException)
{
Console.WriteLine("Unable to convert {0} to Int64.", value);
}
try
{
UInt64 ulValue = (ulong)value;
Console.WriteLine("{0} ({1}) --> {2} (0x{2:X16}) ({3})",
value, value.GetType().Name,
ulValue, ulValue.GetType().Name);
}
catch (OverflowException)
{
Console.WriteLine("Unable to convert {0} to UInt64.", value);
}
try
{
Decimal dValue = (decimal)value;
Console.WriteLine("{0} ({1}) --> {2} ({3})",
value, value.GetType().Name,
dValue, dValue.GetType().Name);
}
catch (OverflowException)
{
Console.WriteLine("Unable to convert {0} to Decimal.", value);
}
try
{
Single sValue = (float)value;
Console.WriteLine("{0} ({1}) --> {2} ({3})",
value, value.GetType().Name,
sValue, sValue.GetType().Name);
}
catch (OverflowException)
{
Console.WriteLine("Unable to convert {0} to Single.", value);
}
Console.WriteLine();
}
}
}
}
// The example displays the following output for conversions performed
// in a checked context:
// Unable to convert -1.79769313486232E+308 to Int64.
// Unable to convert -1.79769313486232E+308 to UInt64.
// Unable to convert -1.79769313486232E+308 to Decimal.
// -1.79769313486232E+308 (Double) --> -Infinity (Single)
//
// -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
// Unable to convert -67890.1234 to UInt64.
// -67890.1234 (Double) --> -67890.1234 (Decimal)
// -67890.1234 (Double) --> -67890.13 (Single)
//
// -12345.6789 (Double) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
// Unable to convert -12345.6789 to UInt64.
// -12345.6789 (Double) --> -12345.6789 (Decimal)
// -12345.6789 (Double) --> -12345.68 (Single)
//
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (Int64)
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (UInt64)
// 12345.6789 (Double) --> 12345.6789 (Decimal)
// 12345.6789 (Double) --> 12345.68 (Single)
//
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
// 67890.1234 (Double) --> 67890.1234 (Decimal)
// 67890.1234 (Double) --> 67890.13 (Single)
//
// Unable to convert 1.79769313486232E+308 to Int64.
// Unable to convert 1.79769313486232E+308 to UInt64.
// Unable to convert 1.79769313486232E+308 to Decimal.
// 1.79769313486232E+308 (Double) --> Infinity (Single)
//
// Unable to convert NaN to Int64.
// Unable to convert NaN to UInt64.
// Unable to convert NaN to Decimal.
// NaN (Double) --> NaN (Single)
//
// Unable to convert Infinity to Int64.
// Unable to convert Infinity to UInt64.
// Unable to convert Infinity to Decimal.
// Infinity (Double) --> Infinity (Single)
//
// Unable to convert -Infinity to Int64.
// Unable to convert -Infinity to UInt64.
// Unable to convert -Infinity to Decimal.
// -Infinity (Double) --> -Infinity (Single)
// The example displays the following output for conversions performed
// in an unchecked context:
// -1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// -1.79769313486232E+308 (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
// Unable to convert -1.79769313486232E+308 to Decimal.
// -1.79769313486232E+308 (Double) --> -Infinity (Single)
//
// -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
// -67890.1234 (Double) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
// -67890.1234 (Double) --> -67890.1234 (Decimal)
// -67890.1234 (Double) --> -67890.13 (Single)
//
// -12345.6789 (Double) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
// -12345.6789 (Double) --> 18446744073709539271 (0xFFFFFFFFFFFFCFC7) (UInt64)
// -12345.6789 (Double) --> -12345.6789 (Decimal)
// -12345.6789 (Double) --> -12345.68 (Single)
//
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (Int64)
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (UInt64)
// 12345.6789 (Double) --> 12345.6789 (Decimal)
// 12345.6789 (Double) --> 12345.68 (Single)
//
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
// 67890.1234 (Double) --> 67890.1234 (Decimal)
// 67890.1234 (Double) --> 67890.13 (Single)
//
// 1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// 1.79769313486232E+308 (Double) --> 0 (0x0000000000000000) (UInt64)
// Unable to convert 1.79769313486232E+308 to Decimal.
// 1.79769313486232E+308 (Double) --> Infinity (Single)
//
// NaN (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// NaN (Double) --> 0 (0x0000000000000000) (UInt64)
// Unable to convert NaN to Decimal.
// NaN (Double) --> NaN (Single)
//
// Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// Infinity (Double) --> 0 (0x0000000000000000) (UInt64)
// Unable to convert Infinity to Decimal.
// Infinity (Double) --> Infinity (Single)
//
// -Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// -Infinity (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
// Unable to convert -Infinity to Decimal.
// -Infinity (Double) --> -Infinity (Single)
open System
open Checked
let values =
[| Double.MinValue; -67890.1234; -12345.6789
12345.6789; 67890.1234; Double.MaxValue
Double.NaN; Double.PositiveInfinity;
Double.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."
try
let sValue = float32 value
printfn $"{value} ({value.GetType().Name}) --> {sValue} ({sValue.GetType().Name})"
with :? OverflowException ->
printfn $"Unable to convert {value} to Single."
printfn ""
// The example displays the following output for conversions performed
// in a checked context:
// Unable to convert -1.79769313486232E+308 to Int64.
// Unable to convert -1.79769313486232E+308 to UInt64.
// Unable to convert -1.79769313486232E+308 to Decimal.
// -1.79769313486232E+308 (Double) --> -Infinity (Single)
//
// -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
// Unable to convert -67890.1234 to UInt64.
// -67890.1234 (Double) --> -67890.1234 (Decimal)
// -67890.1234 (Double) --> -67890.13 (Single)
//
// -12345.6789 (Double) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
// Unable to convert -12345.6789 to UInt64.
// -12345.6789 (Double) --> -12345.6789 (Decimal)
// -12345.6789 (Double) --> -12345.68 (Single)
//
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (Int64)
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (UInt64)
// 12345.6789 (Double) --> 12345.6789 (Decimal)
// 12345.6789 (Double) --> 12345.68 (Single)
//
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
// 67890.1234 (Double) --> 67890.1234 (Decimal)
// 67890.1234 (Double) --> 67890.13 (Single)
//
// Unable to convert 1.79769313486232E+308 to Int64.
// Unable to convert 1.79769313486232E+308 to UInt64.
// Unable to convert 1.79769313486232E+308 to Decimal.
// 1.79769313486232E+308 (Double) --> Infinity (Single)
//
// Unable to convert NaN to Int64.
// Unable to convert NaN to UInt64.
// Unable to convert NaN to Decimal.
// NaN (Double) --> NaN (Single)
//
// Unable to convert Infinity to Int64.
// Unable to convert Infinity to UInt64.
// Unable to convert Infinity to Decimal.
// Infinity (Double) --> Infinity (Single)
//
// Unable to convert -Infinity to Int64.
// Unable to convert -Infinity to UInt64.
// Unable to convert -Infinity to Decimal.
// -Infinity (Double) --> -Infinity (Single)
// The example displays the following output for conversions performed
// in an unchecked context:
// -1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// -1.79769313486232E+308 (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
// Unable to convert -1.79769313486232E+308 to Decimal.
// -1.79769313486232E+308 (Double) --> -Infinity (Single)
//
// -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
// -67890.1234 (Double) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
// -67890.1234 (Double) --> -67890.1234 (Decimal)
// -67890.1234 (Double) --> -67890.13 (Single)
//
// -12345.6789 (Double) --> -12345 (0xFFFFFFFFFFFFCFC7) (Int64)
// -12345.6789 (Double) --> 18446744073709539271 (0xFFFFFFFFFFFFCFC7) (UInt64)
// -12345.6789 (Double) --> -12345.6789 (Decimal)
// -12345.6789 (Double) --> -12345.68 (Single)
//
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (Int64)
// 12345.6789 (Double) --> 12345 (0x0000000000003039) (UInt64)
// 12345.6789 (Double) --> 12345.6789 (Decimal)
// 12345.6789 (Double) --> 12345.68 (Single)
//
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
// 67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
// 67890.1234 (Double) --> 67890.1234 (Decimal)
// 67890.1234 (Double) --> 67890.13 (Single)
//
// 1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// 1.79769313486232E+308 (Double) --> 0 (0x0000000000000000) (UInt64)
// Unable to convert 1.79769313486232E+308 to Decimal.
// 1.79769313486232E+308 (Double) --> Infinity (Single)
//
// NaN (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// NaN (Double) --> 0 (0x0000000000000000) (UInt64)
// Unable to convert NaN to Decimal.
// NaN (Double) --> NaN (Single)
//
// Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// Infinity (Double) --> 0 (0x0000000000000000) (UInt64)
// Unable to convert Infinity to Decimal.
// Infinity (Double) --> Infinity (Single)
//
// -Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
// -Infinity (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
// Unable to convert -Infinity to Decimal.
// -Infinity (Double) --> -Infinity (Single)
Module Example6
Public Sub Main()
Dim values() As Double = {Double.MinValue, -67890.1234, -12345.6789,
12345.6789, 67890.1234, Double.MaxValue,
Double.NaN, Double.PositiveInfinity,
Double.NegativeInfinity}
For Each value In values
Try
Dim lValue As Int64 = 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
Try
Dim sValue As Single = CSng(value)
Console.WriteLine("{0} ({1}) --> {2} ({3})",
value, value.GetType().Name,
sValue, sValue.GetType().Name)
Catch e As OverflowException
Console.WriteLine("Unable to convert {0} to Single.", value)
End Try
Console.WriteLine()
Next
End Sub
End Module
' The example displays the following output for conversions performed
' in a checked context:
' Unable to convert -1.79769313486232E+308 to Int64.
' Unable to convert -1.79769313486232E+308 to UInt64.
' Unable to convert -1.79769313486232E+308 to Decimal.
' -1.79769313486232E+308 (Double) --> -Infinity (Single)
'
' -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
' Unable to convert -67890.1234 to UInt64.
' -67890.1234 (Double) --> -67890.1234 (Decimal)
' -67890.1234 (Double) --> -67890.13 (Single)
'
' -12345.6789 (Double) --> -12346 (0xFFFFFFFFFFFFCFC6) (Int64)
' Unable to convert -12345.6789 to UInt64.
' -12345.6789 (Double) --> -12345.6789 (Decimal)
' -12345.6789 (Double) --> -12345.68 (Single)
'
' 12345.6789 (Double) --> 12346 (0x000000000000303A) (Int64)
' 12345.6789 (Double) --> 12346 (0x000000000000303A) (UInt64)
' 12345.6789 (Double) --> 12345.6789 (Decimal)
' 12345.6789 (Double) --> 12345.68 (Single)
'
' 67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
' 67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
' 67890.1234 (Double) --> 67890.1234 (Decimal)
' 67890.1234 (Double) --> 67890.13 (Single)
'
' Unable to convert 1.79769313486232E+308 to Int64.
' Unable to convert 1.79769313486232E+308 to UInt64.
' Unable to convert 1.79769313486232E+308 to Decimal.
' 1.79769313486232E+308 (Double) --> Infinity (Single)
'
' Unable to convert NaN to Int64.
' Unable to convert NaN to UInt64.
' Unable to convert NaN to Decimal.
' NaN (Double) --> NaN (Single)
'
' Unable to convert Infinity to Int64.
' Unable to convert Infinity to UInt64.
' Unable to convert Infinity to Decimal.
' Infinity (Double) --> Infinity (Single)
'
' Unable to convert -Infinity to Int64.
' Unable to convert -Infinity to UInt64.
' Unable to convert -Infinity to Decimal.
' -Infinity (Double) --> -Infinity (Single)
' The example displays the following output for conversions performed
' in an unchecked context:
' -1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
' -1.79769313486232E+308 (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
' Unable to convert -1.79769313486232E+308 to Decimal.
' -1.79769313486232E+308 (Double) --> -Infinity (Single)
'
' -67890.1234 (Double) --> -67890 (0xFFFFFFFFFFFEF6CE) (Int64)
' -67890.1234 (Double) --> 18446744073709483726 (0xFFFFFFFFFFFEF6CE) (UInt64)
' -67890.1234 (Double) --> -67890.1234 (Decimal)
' -67890.1234 (Double) --> -67890.13 (Single)
'
' -12345.6789 (Double) --> -12346 (0xFFFFFFFFFFFFCFC6) (Int64)
' -12345.6789 (Double) --> 18446744073709539270 (0xFFFFFFFFFFFFCFC6) (UInt64)
' -12345.6789 (Double) --> -12345.6789 (Decimal)
' -12345.6789 (Double) --> -12345.68 (Single)
'
' 12345.6789 (Double) --> 12346 (0x000000000000303A) (Int64)
' 12345.6789 (Double) --> 12346 (0x000000000000303A) (UInt64)
' 12345.6789 (Double) --> 12345.6789 (Decimal)
' 12345.6789 (Double) --> 12345.68 (Single)
'
' 67890.1234 (Double) --> 67890 (0x0000000000010932) (Int64)
' 67890.1234 (Double) --> 67890 (0x0000000000010932) (UInt64)
' 67890.1234 (Double) --> 67890.1234 (Decimal)
' 67890.1234 (Double) --> 67890.13 (Single)
'
' 1.79769313486232E+308 (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
' 1.79769313486232E+308 (Double) --> 0 (0x0000000000000000) (UInt64)
' Unable to convert 1.79769313486232E+308 to Decimal.
' 1.79769313486232E+308 (Double) --> Infinity (Single)
'
' NaN (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
' NaN (Double) --> 0 (0x0000000000000000) (UInt64)
' Unable to convert NaN to Decimal.
' NaN (Double) --> NaN (Single)
'
' Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
' Infinity (Double) --> 0 (0x0000000000000000) (UInt64)
' Unable to convert Infinity to Decimal.
' Infinity (Double) --> Infinity (Single)
'
' -Infinity (Double) --> -9223372036854775808 (0x8000000000000000) (Int64)
' -Infinity (Double) --> 9223372036854775808 (0x8000000000000000) (UInt64)
' Unable to convert -Infinity to Decimal.
' -Infinity (Double) --> -Infinity (Single)
Sayısal türlerin dönüştürülmesi hakkında daha fazla bilgi için bkz . .NET'te Tür Dönüştürme ve Tür Dönüştürme Tabloları.
Kayan nokta işlevleri
Yapı Double ve ilgili türler aşağıdaki alanlarda işlem gerçekleştirmek için yöntemler sağlar:
Değerlerin karşılaştırması. İki değerin Equals eşit olup olmadığını belirlemek için yöntemini veya CompareTo iki Double değer arasındaki ilişkiyi belirlemek için yöntemini çağırabilirsiniz.
Yapısı Double , tam bir karşılaştırma işleçleri kümesini de destekler. Örneğin, eşitliği veya eşitsizliği test edebilir veya bir değerin başka bir değerden büyük mü yoksa başka bir değere eşit mi olduğunu belirleyebilirsiniz. İşlenenlerden biri dışında bir sayısal türse Double, karşılaştırma gerçekleştirilmeden önce öğesine Double dönüştürülür.
Uyarı
Duyarlık farklılıkları nedeniyle, eşit olmasını beklediğiniz iki Double değerin eşit olmadığı ortaya çıkabilir ve bu da karşılaştırmanın sonucunu etkiler. İki Double değeri karşılaştırma hakkında daha fazla bilgi için Eşitlik testi bölümüne bakın.
Ayrıca, bu özel değerleri test etmek için , IsInfinity, IsPositiveInfinityve IsNegativeInfinity yöntemlerini çağırabilirsinizIsNaN.
Matematiksel işlemler. Toplama, çıkarma, çarpma ve bölme gibi yaygın aritmetik işlemler, yöntemler yerine dil derleyicileri ve Ortak Ara Dil (CIL) yönergeleri tarafından Double uygulanır. Matematiksel işlemdeki işlenenlerden biri dışında bir sayısal türse Double, işlemi gerçekleştirmeden önce öğesine Double dönüştürülür. İşlemin sonucu da bir Double değerdir.
Sınıfındaki (
Shared
Visual Basic'te) yöntemleri System.Math çağrılarakstatic
diğer matematiksel işlemler gerçekleştirilebilir. Aritmetik (, , ve gibiMath.Abs), geometri (ve gibi Math.CosMath.Sin) ve kalkülüs (gibiMath.Log) için yaygın olarak kullanılan ek yöntemleri içerir. Math.SignMath.SqrtAyrıca, bir Double değerdeki tek tek bitleri de işleyebilirsiniz. yöntemi, BitConverter.DoubleToInt64Bits değerin Double bit desenini 64 bitlik bir tamsayıda korur. yöntemi bit BitConverter.GetBytes(Double) desenini bayt dizisinde döndürür.
Yuvarlama. Yuvarlama genellikle kayan nokta gösterimi ve duyarlık sorunlarının neden olduğu değerler arasındaki farkların etkisini azaltmak için bir teknik olarak kullanılır. yöntemini çağırarak Math.Round bir Double değeri yuvarlayabilirsiniz.
Biçimlendirme. Yöntemini çağırarak ToString veya bileşik biçimlendirme özelliğini kullanarak bir Double değeri dize gösterimine dönüştürebilirsiniz. Biçim dizelerinin kayan nokta değerlerinin dize gösterimini nasıl denetlediğini öğrenmek için Standart Sayısal Biçim Dizeleri ve Özel Sayısal Biçim Dizeleri konularına bakın.
Dizeleri ayrıştırma. Veya TryParse yöntemini çağırarak kayan nokta değerinin dize gösterimini bir Double değere Parse dönüştürebilirsiniz. Ayrıştırma işlemi başarısız olursa yöntemi Parse bir özel durum oluştururken TryParse yöntemi döndürür
false
.Tür dönüştürme. yapısı Double , arabirim için iki standart .NET veri türü arasında dönüştürmeyi IConvertible destekleyen açık bir arabirim uygulaması sağlar. Dil derleyicileri, diğer tüm standart sayısal türlerin değerlerinin değerlere örtük olarak dönüştürülmesi de Double desteklenir. Herhangi bir standart sayısal türdeki bir değerin bir değerine dönüştürülmesi Double bir genişletme dönüştürmesidir ve bir atama işlecinin veya dönüştürme yönteminin kullanıcısının kullanılmasını gerektirmez,
Ancak ve Single değerlerinin dönüştürülmesi Int64 duyarlık kaybı içerebilir. Aşağıdaki tabloda, bu türlerin her biri için duyarlık farklılıkları listelenmiştir:
Tür En yüksek duyarlık İç duyarlık Double 15 17 Int64 19 ondalık basamak 19 ondalık basamak Single 7 ondalık basamak 9 ondalık basamak Duyarlık sorunu en sık değerlere Double dönüştürülen değerleri etkilerSingle. Aşağıdaki örnekte, aynı bölme işlemleri tarafından üretilen iki değer eşit değildir çünkü değerlerden biri tek duyarlıklı kayan nokta değerine dönüştürülür Double.
using System; public class Example13 { public static void Main() { Double value = .1; Double result1 = value * 10; Double result2 = 0; for (int ctr = 1; ctr <= 10; ctr++) result2 += value; Console.WriteLine(".1 * 10: {0:R}", result1); Console.WriteLine(".1 Added 10 times: {0:R}", result2); } } // The example displays the following output: // .1 * 10: 1 // .1 Added 10 times: 0.99999999999999989
let value = 0.1 let result1 = value * 10. let mutable result2 = 0. for i = 1 to 10 do result2 <- result2 + value printfn $".1 * 10: {result1:R}" printfn $".1 Added 10 times: {result2:R}" // The example displays the following output: // .1 * 10: 1 // .1 Added 10 times: 0.99999999999999989
Module Example14 Public Sub Main() Dim value As Double = 0.1 Dim result1 As Double = value * 10 Dim result2 As Double For ctr As Integer = 1 To 10 result2 += value Next Console.WriteLine(".1 * 10: {0:R}", result1) Console.WriteLine(".1 Added 10 times: {0:R}", result2) End Sub End Module ' The example displays the following output: ' .1 * 10: 1 ' .1 Added 10 times: 0.99999999999999989
Örnekler
Aşağıdaki kod örneğinde kullanımı gösterilmektedir Double:
// The Temperature class stores the temperature as a Double
// and delegates most of the functionality to the Double
// implementation.
public class Temperature : IComparable, IFormattable
{
// IComparable.CompareTo implementation.
public int CompareTo(object obj) {
if (obj == null) return 1;
Temperature temp = obj as Temperature;
if (obj != null)
return m_value.CompareTo(temp.m_value);
else
throw new ArgumentException("object is not a Temperature");
}
// IFormattable.ToString implementation.
public string ToString(string format, IFormatProvider provider) {
if( format != null ) {
if( format.Equals("F") ) {
return String.Format("{0}'F", this.Value.ToString());
}
if( format.Equals("C") ) {
return String.Format("{0}'C", this.Celsius.ToString());
}
}
return m_value.ToString(format, provider);
}
// Parses the temperature from a string in the form
// [ws][sign]digits['F|'C][ws]
public static Temperature Parse(string s, NumberStyles styles, IFormatProvider provider) {
Temperature temp = new Temperature();
if( s.TrimEnd(null).EndsWith("'F") ) {
temp.Value = Double.Parse( s.Remove(s.LastIndexOf('\''), 2), styles, provider);
}
else if( s.TrimEnd(null).EndsWith("'C") ) {
temp.Celsius = Double.Parse( s.Remove(s.LastIndexOf('\''), 2), styles, provider);
}
else {
temp.Value = Double.Parse(s, styles, provider);
}
return temp;
}
// The value holder
protected double m_value;
public double Value {
get {
return m_value;
}
set {
m_value = value;
}
}
public double Celsius {
get {
return (m_value-32.0)/1.8;
}
set {
m_value = 1.8*value+32.0;
}
}
}
// The Temperature class stores the temperature as a Double
// and delegates most of the functionality to the Double
// implementation.
type Temperature() =
member val Value = 0. with get, set
member this.Celsius
with get () = (this.Value - 32.) / 1.8
and set (value) =
this.Value <- 1.8 * value + 32.
// Parses the temperature from a string in the form
// [ws][sign]digits['F|'C][ws]
static member Parse(s: string, styles: NumberStyles, provider: IFormatProvider) =
let temp = Temperature()
if s.TrimEnd(null).EndsWith "'F" then
temp.Value <- Double.Parse(s.Remove(s.LastIndexOf '\'', 2), styles, provider)
elif s.TrimEnd(null).EndsWith "'C" then
temp.Celsius <- Double.Parse(s.Remove(s.LastIndexOf '\'', 2), styles, provider)
else
temp.Value <- Double.Parse(s, styles, provider)
temp
interface IComparable with
// IComparable.CompareTo implementation.
member this.CompareTo(obj: obj) =
match obj with
| null -> 1
| :? Temperature as temp ->
this.Value.CompareTo temp.Value
| _ ->
invalidArg "obj" "object is not a Temperature"
interface IFormattable with
// IFormattable.ToString implementation.
member this.ToString(format: string, provider: IFormatProvider) =
match format with
| "F" ->
$"{this.Value}'F"
| "C" ->
$"{this.Celsius}'C"
| _ ->
this.Value.ToString(format, provider)
' Temperature class stores the value as Double
' and delegates most of the functionality
' to the Double implementation.
Public Class Temperature
Implements IComparable, IFormattable
Public Overloads Function CompareTo(ByVal obj As Object) As Integer _
Implements IComparable.CompareTo
If TypeOf obj Is Temperature Then
Dim temp As Temperature = CType(obj, Temperature)
Return m_value.CompareTo(temp.m_value)
End If
Throw New ArgumentException("object is not a Temperature")
End Function
Public Overloads Function ToString(ByVal format As String, ByVal provider As IFormatProvider) As String _
Implements IFormattable.ToString
If Not (format Is Nothing) Then
If format.Equals("F") Then
Return [String].Format("{0}'F", Me.Value.ToString())
End If
If format.Equals("C") Then
Return [String].Format("{0}'C", Me.Celsius.ToString())
End If
End If
Return m_value.ToString(format, provider)
End Function
' Parses the temperature from a string in form
' [ws][sign]digits['F|'C][ws]
Public Shared Function Parse(ByVal s As String, ByVal styles As NumberStyles, ByVal provider As IFormatProvider) As Temperature
Dim temp As New Temperature()
If s.TrimEnd().EndsWith("'F") Then
temp.Value = Double.Parse(s.Remove(s.LastIndexOf("'"c), 2), styles, provider)
Else
If s.TrimEnd().EndsWith("'C") Then
temp.Celsius = Double.Parse(s.Remove(s.LastIndexOf("'"c), 2), styles, provider)
Else
temp.Value = Double.Parse(s, styles, provider)
End If
End If
Return temp
End Function
' The value holder
Protected m_value As Double
Public Property Value() As Double
Get
Return m_value
End Get
Set(ByVal Value As Double)
m_value = Value
End Set
End Property
Public Property Celsius() As Double
Get
Return (m_value - 32) / 1.8
End Get
Set(ByVal Value As Double)
m_value = Value * 1.8 + 32
End Set
End Property
End Class