为什么我会丢失信息?
Why am I losing information?
当我发现它时我正在编码:
double v = 555.55;
int v2 = (int)Math.Floor(v / 100.0);
double v3 = v2 * 100;
double v4 = v - v2 * 100;
double v5 = v - v3;
最后,代码说:
v = 555.55
v2 = 5
v3 = 500
v4 = 55.549999999999955
v5 = 55.549999999999955
那么,为什么会发生这种情况,我该如何解决?
好吧,将 double 转换为 int 后,您将丢失信息,因为 int 是整数,因此小数点后的所有内容都会被删除。
嗯,double v = 555.55
(即double v = 0.55
)的小数部分是一个周期性二进制分数
无法准确表示。我们有什么选择?让我们对 555.55
进行尽可能小的更改
(即我们更改 555.55
的最后一位):
double v = 555.55;
int v2 = (int)Math.Floor(v / 100.0);
double v4 = v - v2 * 100;
// Here we increment the last bit of v (minimum possible change)
byte[] bytes = BitConverter.GetBytes(v);
bytes[0] = (byte) (bytes[0] + 1);
double d = BitConverter.ToDouble(bytes);
double dv = d - v2 * 100;
string result = string.Join(Environment.NewLine,
$" v = {v:R}",
$"v4 = {v4:R}",
$" v' = {d:R}",
$"v4' = {dv:R}");
Console.Write(result);
结果:
v = 555.55
v4 = 55.549999999999955
v' = 555.5500000000001
v4' = 55.55000000000007
所以我们唯一的选择是 55.549999999999955
或 55.55000000000007
;请注意,55.549999999999955
更好 (4.5e-14
< 7.0e-14
).
如何修复它?如您所见,浮点数算法带来舍入误差;通常我们可以将 double
更改为 decimal
如果 555.55
是某种 货币 值(例如,美元和美分),这是标准做法:
decimal v = 555.55m;
int v2 = (int)Math.Floor(v / 100m);
decimal v3 = v2 * 100;
decimal v4 = v - v2 * 100;
decimal v5 = v - v3;
string result = string.Join(Environment.NewLine,
$" v = {v}",
$"v2 = {v2}",
$"v3 = {v3}",
$"v4 = {v4}",
$"v5 = {v5}");
Console.Write(result);
结果:
v = 555.55
v2 = 5
v3 = 500
v4 = 55.55
v5 = 55.55
当我发现它时我正在编码:
double v = 555.55;
int v2 = (int)Math.Floor(v / 100.0);
double v3 = v2 * 100;
double v4 = v - v2 * 100;
double v5 = v - v3;
最后,代码说:
v = 555.55
v2 = 5
v3 = 500
v4 = 55.549999999999955
v5 = 55.549999999999955
那么,为什么会发生这种情况,我该如何解决?
好吧,将 double 转换为 int 后,您将丢失信息,因为 int 是整数,因此小数点后的所有内容都会被删除。
嗯,double v = 555.55
(即double v = 0.55
)的小数部分是一个周期性二进制分数
无法准确表示。我们有什么选择?让我们对 555.55
进行尽可能小的更改
(即我们更改 555.55
的最后一位):
double v = 555.55;
int v2 = (int)Math.Floor(v / 100.0);
double v4 = v - v2 * 100;
// Here we increment the last bit of v (minimum possible change)
byte[] bytes = BitConverter.GetBytes(v);
bytes[0] = (byte) (bytes[0] + 1);
double d = BitConverter.ToDouble(bytes);
double dv = d - v2 * 100;
string result = string.Join(Environment.NewLine,
$" v = {v:R}",
$"v4 = {v4:R}",
$" v' = {d:R}",
$"v4' = {dv:R}");
Console.Write(result);
结果:
v = 555.55
v4 = 55.549999999999955
v' = 555.5500000000001
v4' = 55.55000000000007
所以我们唯一的选择是 55.549999999999955
或 55.55000000000007
;请注意,55.549999999999955
更好 (4.5e-14
< 7.0e-14
).
如何修复它?如您所见,浮点数算法带来舍入误差;通常我们可以将 double
更改为 decimal
如果 555.55
是某种 货币 值(例如,美元和美分),这是标准做法:
decimal v = 555.55m;
int v2 = (int)Math.Floor(v / 100m);
decimal v3 = v2 * 100;
decimal v4 = v - v2 * 100;
decimal v5 = v - v3;
string result = string.Join(Environment.NewLine,
$" v = {v}",
$"v2 = {v2}",
$"v3 = {v3}",
$"v4 = {v4}",
$"v5 = {v5}");
Console.Write(result);
结果:
v = 555.55
v2 = 5
v3 = 500
v4 = 55.55
v5 = 55.55