c# - 为什么我会丢失信息?
问题描述
当我发现它时,我正在编码:
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 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
or 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
推荐阅读
- typescript - 通过 typescript 编译器 API 从导入使用中解析符号定义文件名
- reactjs - index.js:1 警告:上下文消费者使用多个孩子呈现
- git - 为构建机器运行的 Git 命令以使存储库尽可能无故障
- reactjs - React 功能组件状态总是记录初始值
- json - 如何解组不同类型的流
- r - 用多行更改ggplot上的刻度线
- excel - VLOOKUP 多个值
- angular - 存储与随时随地提出请求
- docker - 如何从 Windows 10 连接 Docker-Linux 上的 docker-compose Sql 服务器容器?
- c# - ASP.NET MVC 5 在重定向时丢弃尾随句点