C# で計算機イプシロンを計算する

C 言語での計算機イプシロンを確認する方法を見つけたので、 C# でも実行してみることにしました。

計算機イプシロン

Machine Epsilon

正数 ε に対して 1+ε という演算を行ったとき、記憶領域は有限なので ε が小さすぎると無視されるが、無視されないで加えられる尤も小さい数をマシン・エプシロンと呼んでいる。

Cで学ぶ数値計算アルゴリズム(書籍)

実際に値を 1.0 から半分にしていくと、浮動小数点数の表現上 1.0 とその値を足しても 1.0 とみなされる場合が出てきます。そのときの 1.0 と足して 1.0 とならない直前の値が計算機イプシロンです。

C# で小数を表す基本の型は floatdoubledecimal があるので、すべてについてみていきます。プログラムは単純に型を変えるだけなので、まとめて出してしまいます。ソースコード等はこちらから

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
static void CalcFloatEpsilon()
{
float eps = 1.0f;

while (1.0f + eps / 2.0f > 1.0f)
{
eps /= 2.0f;

Console.WriteLine($"{(1.0f + eps):e30}");
}

Console.WriteLine($"1+eps : {(1.0f + eps):e30}");
Console.WriteLine($"1+eps/2: {(1.0f + eps / 2.0f):e30}");
Console.WriteLine($"float machine epsilon: {eps:e30}");
}

static void CalcDoubleEpsilon()
{
double eps = 1.0;

while (1.0 + eps / 2.0 > 1.0)
{
eps /= 2.0;

Console.WriteLine($"{(1.0 + eps):e30}");
}

Console.WriteLine($"1+eps : {(1.0 + eps):e30}");
Console.WriteLine($"1+eps/2: {(1.0 + eps / 2.0):e30}");
Console.WriteLine($"double machine epsilon: {eps:e30}");
}

static void CalcDecimalEpsilon()
{
decimal eps = 1.0m;

while (1.0m + eps / 2.0m > 1.0m)
{
eps /= 2.0m;

Console.WriteLine($"{(1.0m + eps):e30}");
}

Console.WriteLine($"1+eps : {(1.0m + eps):e30}");
Console.WriteLine($"1+eps/2: {(1.0m + eps / 2.0m):e30}");
Console.WriteLine($"decimal machine epsilon: {eps:e30}");
}

計算結果は次の通りです。(長い…)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
1.500000000000000000000000000000e+000
1.250000000000000000000000000000e+000
1.125000000000000000000000000000e+000
1.062500000000000000000000000000e+000
1.031250000000000000000000000000e+000
1.015625000000000000000000000000e+000
1.007812500000000000000000000000e+000
1.003906250000000000000000000000e+000
1.001953130000000000000000000000e+000
1.000976560000000000000000000000e+000
1.000488280000000000000000000000e+000
1.000244140000000000000000000000e+000
1.000122070000000000000000000000e+000
1.000061040000000000000000000000e+000
1.000030520000000000000000000000e+000
1.000015260000000000000000000000e+000
1.000007630000000000000000000000e+000
1.000003810000000000000000000000e+000
1.000001910000000000000000000000e+000
1.000000950000000000000000000000e+000
1.000000480000000000000000000000e+000
1.000000240000000000000000000000e+000
1.000000120000000000000000000000e+000
1+eps : 1.000000120000000000000000000000e+000
1+eps/2: 1.000000000000000000000000000000e+000
float machine epsilon: 1.192092900000000000000000000000e-007

1.500000000000000000000000000000e+000
1.250000000000000000000000000000e+000
1.125000000000000000000000000000e+000
1.062500000000000000000000000000e+000
1.031250000000000000000000000000e+000
1.015625000000000000000000000000e+000
1.007812500000000000000000000000e+000
1.003906250000000000000000000000e+000
1.001953125000000000000000000000e+000
1.000976562500000000000000000000e+000
1.000488281250000000000000000000e+000
1.000244140625000000000000000000e+000
1.000122070312500000000000000000e+000
1.000061035156250000000000000000e+000
1.000030517578125000000000000000e+000
1.000015258789062500000000000000e+000
1.000007629394531300000000000000e+000
1.000003814697265600000000000000e+000
1.000001907348632800000000000000e+000
1.000000953674316400000000000000e+000
1.000000476837158200000000000000e+000
1.000000238418579100000000000000e+000
1.000000119209289600000000000000e+000
1.000000059604644800000000000000e+000
1.000000029802322400000000000000e+000
1.000000014901161200000000000000e+000
1.000000007450580600000000000000e+000
1.000000003725290300000000000000e+000
1.000000001862645100000000000000e+000
1.000000000931322600000000000000e+000
1.000000000465661300000000000000e+000
1.000000000232830600000000000000e+000
1.000000000116415300000000000000e+000
1.000000000058207700000000000000e+000
1.000000000029103800000000000000e+000
1.000000000014551900000000000000e+000
1.000000000007276000000000000000e+000
1.000000000003638000000000000000e+000
1.000000000001819000000000000000e+000
1.000000000000909500000000000000e+000
1.000000000000454700000000000000e+000
1.000000000000227400000000000000e+000
1.000000000000113700000000000000e+000
1.000000000000056800000000000000e+000
1.000000000000028400000000000000e+000
1.000000000000014200000000000000e+000
1.000000000000007100000000000000e+000
1.000000000000003600000000000000e+000
1.000000000000001800000000000000e+000
1.000000000000000900000000000000e+000
1.000000000000000400000000000000e+000
1.000000000000000200000000000000e+000
1+eps : 1.000000000000000200000000000000e+000
1+eps/2: 1.000000000000000000000000000000e+000
double machine epsilon: 2.220446049250313100000000000000e-016

1.500000000000000000000000000000e+000
1.250000000000000000000000000000e+000
1.125000000000000000000000000000e+000
1.062500000000000000000000000000e+000
1.031250000000000000000000000000e+000
1.015625000000000000000000000000e+000
1.007812500000000000000000000000e+000
1.003906250000000000000000000000e+000
1.001953125000000000000000000000e+000
1.000976562500000000000000000000e+000
1.000488281250000000000000000000e+000
1.000244140625000000000000000000e+000
1.000122070312500000000000000000e+000
1.000061035156250000000000000000e+000
1.000030517578125000000000000000e+000
1.000015258789062500000000000000e+000
1.000007629394531250000000000000e+000
1.000003814697265625000000000000e+000
1.000001907348632812500000000000e+000
1.000000953674316406250000000000e+000
1.000000476837158203125000000000e+000
1.000000238418579101562500000000e+000
1.000000119209289550781250000000e+000
1.000000059604644775390625000000e+000
1.000000029802322387695312500000e+000
1.000000014901161193847656250000e+000
1.000000007450580596923828125000e+000
1.000000003725290298461914062500e+000
1.000000001862645149230957031200e+000
1.000000000931322574615478515600e+000
1.000000000465661287307739257800e+000
1.000000000232830643653869628900e+000
1.000000000116415321826934814400e+000
1.000000000058207660913467407200e+000
1.000000000029103830456733703600e+000
1.000000000014551915228366851800e+000
1.000000000007275957614183425900e+000
1.000000000003637978807091713000e+000
1.000000000001818989403545856500e+000
1.000000000000909494701772928200e+000
1.000000000000454747350886464100e+000
1.000000000000227373675443232000e+000
1.000000000000113686837721616000e+000
1.000000000000056843418860808000e+000
1.000000000000028421709430404000e+000
1.000000000000014210854715202000e+000
1.000000000000007105427357601000e+000
1.000000000000003552713678800500e+000
1.000000000000001776356839400200e+000
1.000000000000000888178419700100e+000
1.000000000000000444089209850000e+000
1.000000000000000222044604925000e+000
1.000000000000000111022302462500e+000
1.000000000000000055511151231200e+000
1.000000000000000027755575615600e+000
1.000000000000000013877787807800e+000
1.000000000000000006938893903900e+000
1.000000000000000003469446952000e+000
1.000000000000000001734723476000e+000
1.000000000000000000867361738000e+000
1.000000000000000000433680869000e+000
1.000000000000000000216840434500e+000
1.000000000000000000108420217200e+000
1.000000000000000000054210108600e+000
1.000000000000000000027105054300e+000
1.000000000000000000013552527200e+000
1.000000000000000000006776263600e+000
1.000000000000000000003388131800e+000
1.000000000000000000001694065900e+000
1.000000000000000000000847033000e+000
1.000000000000000000000423516500e+000
1.000000000000000000000211758200e+000
1.000000000000000000000105879100e+000
1.000000000000000000000052939600e+000
1.000000000000000000000026469800e+000
1.000000000000000000000013234900e+000
1.000000000000000000000006617400e+000
1.000000000000000000000003308700e+000
1.000000000000000000000001654400e+000
1.000000000000000000000000827200e+000
1.000000000000000000000000413600e+000
1.000000000000000000000000206800e+000
1.000000000000000000000000103400e+000
1.000000000000000000000000051700e+000
1.000000000000000000000000025800e+000
1.000000000000000000000000012900e+000
1.000000000000000000000000006400e+000
1.000000000000000000000000003200e+000
1.000000000000000000000000001600e+000
1.000000000000000000000000000800e+000
1.000000000000000000000000000400e+000
1.000000000000000000000000000200e+000
1.000000000000000000000000000100e+000
1+eps : 1.000000000000000000000000000100e+000
1+eps/2: 1.000000000000000000000000000000e+000
decimal machine epsilon: 1.000000000000000000000000000000e-028

各型での ε をまとめると下のようになります。

計算機イプシロン( ε )
float 1.192092900000000000000000000000e-007
double 2.220446049250313100000000000000e-016
decimal 1.000000000000000000000000000000e-028

ISO に準拠しているため floatdouble は C 言語など、他の言語のときと同じ結果となっています。
さすがの decimal という感じで、 decimal の正の最小の数字がそのまま ε となっています。