为什么我会丢失信息?

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.54999999999995555.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