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

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
SegmentFault 最新的问题
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Attack and Defense Labs
Attack and Defense Labs
F
Full Disclosure
Vercel News
Vercel News
N
News | PayPal Newsroom
The GitHub Blog
The GitHub Blog
H
Hacker News: Front Page
H
Heimdal Security Blog
P
Privacy International News Feed
博客园 - 司徒正美
Google DeepMind News
Google DeepMind News
N
Netflix TechBlog - Medium
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
Cisco Blogs
L
Lohrmann on Cybersecurity
D
Docker
Recent Announcements
Recent Announcements
Security Archives - TechRepublic
Security Archives - TechRepublic
人人都是产品经理
人人都是产品经理
C
CXSECURITY Database RSS Feed - CXSecurity.com
P
Proofpoint News Feed
T
Tailwind CSS Blog
C
Check Point Blog
博客园 - 叶小钗
Google Online Security Blog
Google Online Security Blog
Martin Fowler
Martin Fowler
Stack Overflow Blog
Stack Overflow Blog
博客园 - 聂微东
S
Secure Thoughts
博客园 - Franky
博客园_首页
阮一峰的网络日志
阮一峰的网络日志
P
Palo Alto Networks Blog
Latest news
Latest news
量子位
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog
Last Week in AI
Last Week in AI
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Cyberwarzone
Cyberwarzone
小众软件
小众软件
Cisco Talos Blog
Cisco Talos Blog
Hacker News: Ask HN
Hacker News: Ask HN
T
Threatpost
T
Tenable Blog
P
Privacy & Cybersecurity Law Blog
WordPress大学
WordPress大学

博客园 - 畅想自由

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