新規記事の投稿を行うことで、非表示にすることが可能です。
2018年05月05日
【012】Decimal型
Decimal型
浮動小数点型である Single(C# では float)型や Double(C# では double)型の場合は、演算が2進数で行われることに起因する誤差により、期待する結果が得られない場合があります。
例えば、
Double a1 = 0.1;
Double a2 = 0;
for (var i = 0; i < 10; i++)
a2 += 0.01;
Console.WriteLine(a1 == a2);
では、True を期待しますが、結果は False となります。
このような不都合を避けるための手段の一つに、Decimal(C# では decimal)型の利用があります。
※Decimal型は、内部的に10進数演算を行うことにより、2進数と10進数の相互変換の際の丸め誤差を防いでいます。
Decimal 型は、Double型より有効桁数が多い(ただし、扱うことのできる値の範囲はDouble型より狭い)ので、財務・金融などの計算に利用されています。
実数値リテラルを Decimal として扱うには、サフィックス m または M を用います。
ただし、整数型は暗黙裏に decimal に変換されるのでサフィックスは不要です。
Decimal b1 = 0.1m;
Decimal b2 = 0;
また、Decimal型と、Double型・Single型の間では暗黙裏の型変換が行われないので、型変換には明示的なキャストが必要です。
Desimal x = 1.23456m;
Double y = (Double)x;
Desimal z = (Decimal)y;
下記のプログラムでは、同じ計算を Double型と Decimal型で行った場合の結果が異なっています。
Decimal型での計算で、期待される結果が得られていることを確認できます。
using System;
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
// Double型
Double a1 = 0.1;
Double a2 = 0;
for (var i = 0; i < 10; i++)
a2 += 0.01;
Console.WriteLine(a1 == a2); // False
// Decimal型
Decimal b1 = 0.1m;
Decimal b2 = 0;
for (var i = 0; i < 10; i++)
b2 += 0.01m;
Console.WriteLine(b1 == b2); // True
}
}
}
【011】文字列型(2)
文字列型(2)
StringBuilder型のオブジェクトから String型の文字列を得るには、ToStringメソッドを利用します。
StringBuilder stb = new StringBuilder("あいうえお");
String str = stb.ToString();
StringBuilder型や Object型は、値型ではなく参照型ですから、「 == 」演算子による比較では参照先の比較が行われます。
ただし、前回《010》も確認しましたが、String型文字列の場合、参照型であるにもかかわらず、「 == 」演算子は、値を比較します。
下記のプログラムにおいて、
String str1 = "abc";
String str2 = "abc";
として作成した文字列は値が等しい(@)だけでなく、参照先も等しいことがわかります(C,E)。
したがって、少なくとも私の使っている処理系では、同じ値の文字列リテラルを同一とみなし、
記憶域上に格納した1つの文字列リテラルを共有しているようです。
StringBuilder stb1 = new StringBuilder("abc");
StringBuilder stb2 = new StringBuilder("abc");
stb1, stb2 は StringBuilder型ですから、「 == 」演算子による比較の結果は False です(A)。
String str3 = stb1.ToString();
String str4 = stb2.ToString();
str3, str4 は、共に"abc"ですから、「 == 」演算子での比較結果は当然 True になります(B)。
一方、ReferenceEqualsメソッドで str3, str4 を比較すると、結果は False です(D)。
このことから、StringBuilder型オブジェクトから ToStringメソッドで得られたString型文字列 str3, str4 の場合は、同じ値であっても、別々に記憶域上に格納されていることがわかります。
using System;
using System.Text;
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
String str1 = "abc";
String str2 = "abc";
StringBuilder stb1 = new StringBuilder("abc");
StringBuilder stb2 = new StringBuilder("abc");
String str3 = stb1.ToString();
String str4 = stb2.ToString();
Console.WriteLine(str1 == str2); // @ True
Console.WriteLine(stb1 == stb2); // A False
Console.WriteLine(str3 == str4); // B True
Console.WriteLine(ReferenceEquals(str1, str2));
// C True
Console.WriteLine(ReferenceEquals(str3, str4));
// D False
Console.WriteLine((Object)str1 == (Object)str2);
// E True
}
}
}