惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

I
InfoQ
博客园 - 司徒正美
爱范儿
爱范儿
F
Fortinet All Blogs
J
Java Code Geeks
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 三生石上(FineUI控件)
腾讯CDC
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
SegmentFault 最新的问题
Microsoft Security Blog
Microsoft Security Blog
T
The Blog of Author Tim Ferriss
V
V2EX
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
云风的 BLOG
云风的 BLOG
T
Tailwind CSS Blog
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
A
About on SuperTechFans
有赞技术团队
有赞技术团队
Y
Y Combinator Blog

博客园 - 畅想自由

HashTable Thinking in Java HTML已经过时了 编写高质量的.NET程序 - 开篇 Do not make joke with me 告别.NET 使用Replace方法时要注意的问题 - 畅想自由 - 博客园 Tomcat 部署问题记录 最近在看的书 经济危机,让我们更加清醒 早上醒来,突然睡不着 IE和FireFox 对动态FORM enctype属性的认识问题 - 畅想自由 不再技术崇拜,精神开始焕发 Vs2003中Grid绑定强类型的问题 青春的岁月我们身不由己,只因着心中燃烧着梦想... 职业规划是什么? 做一个专业的IT管理人才必备的十大能力 Delphi的类与继承 Delphi 与 C#
为什么19.9变成了19.89,不靠谱的 double 类型
畅想自由 · 2010-12-21 · via 博客园 - 畅想自由

    今天财务告诉我线上有个¥19.9的商品,在用户付款时变成了¥19.89,致使公司损失了N个1分钱。我第一反应是不是不靠谱的财付通造成的,因为财付通需要我们把商品金额转换成“分”,这样我们在向财付通传递数据时必须事先对商品价格*100,打电话给财付通,对账后发现数据确实是我们这边就传错了。好吧,来看看我们的问题在那里,查看代码发现有类似这样的一行代码:

int a = (int)(fee *100);

由于我们的fee不会超过2个小数,因此这行代码从表面看不会有什么问题。但感觉肯定是这个转换有精度损失,从而将1990变成了1989 。正在奇怪的时候,发现fee在其他地方被定义成了double类型,就是这个精度不够高的double类型在转换成int时损失了精度。真是太奇怪了,因为如果我们将fee强制转换成精度更高的decimal类型,就不会有问题,其结果就是正确的1990而不是1989。这种精度从表面是看不出来的。

写一段测试代码:

 int a = (int)(19.9 *100);   //19.9默认是double类型
 int b = (int)(19.9M *100 ); //将19.9转换成decimal类型

 Console.WriteLine(a);  //输出:1989

 Console.WriteLine(b);  //输出:1990

怪不得,即使微软都建议进行财务计算时最好使用精度更高的decimal类型。因为double太不靠谱,用它计算的结果会“超出你的期望”。写到这里,其实我也只能怀疑是精度的原因了,因为从测试代码来看,确实很诡异。

当我写完以上的文字,正准备关闭程序的时候,突然想起来财务说过,我们以前有¥9.9的商品都没有出现过这个问题,啊!为什么会这样。难道是程序抽疯了??好吧继续写测试:

int a = (int)(9.9*100);

int b = (int)(9.9M *100);

Console.WriteLine(a); //输出:990 为什么不是想象的:989 ?
Console.WriteLine(b); //输出:990

继续测试:

int a = (int)(29.9*100);  //输出:2990 为什么不是:2989 ?
int b = (int)(29.9M *100); //输出:2990

Console.WriteLine(a);
Console.WriteLine(b);

好吧,先打住吧,我都要疯了,难道我关于精度的怀疑是错误的?

继续加大测试范围:

 double k = 0.0;
 for (int i = 0; i < 50; i++)
 {
              
       int a = (int)((k) * 100);
       int b = (int)((decimal)(k) * 100);
       if (a != b)
       {
           Console.WriteLine(a);
           Console.WriteLine(b);
           Console.WriteLine("————");
       }
       k += 0.9;
  }

输出结果还暂时还看不出是什么规律,求微软的大侠来解释哈。

该文章同时发布在这里:http://jasonjiang.me/archives/44