今天财务告诉我线上有个¥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

posted @ 2010-12-21 22:04 畅想自由 阅读(546) 评论(22) 编辑

据设定的哈希函数H(key)和所选中的处理冲突的方法,将一组关键字映象到一个有限的、地址连续的地址集(区间)上并以关键字在地址集中的“象”作为相应记录在表中的存储位置,这种表被称为哈希表.

posted @ 2010-08-12 21:23 畅想自由 阅读(21) 评论(0) 编辑

  鉴于C#的好书匮乏,建议朋友们在学习C#一段时间后,可以看看 Thinking in Java 这本书。其实这两种语言很多地方是相通的,应该不会感到太多的陌生。这本书对我的帮助就是,强化了我以前一直很匮乏的基础知识,这种知识,平时看不出有多么重要;因为只有在关键的时候,它才发挥巨大的作用。

posted @ 2010-05-22 14:20 畅想自由 阅读(23) 评论(0) 编辑

  HTML已经变得过时,富客户端重现生机。

posted @ 2010-05-09 22:12 畅想自由 阅读(19) 评论(0) 编辑

编写.NET程序也有好几年了,一直在考虑如何才能编写高质量的代码,什么才算是高质量的代码呢? 我觉得至少要具备两个条件:

      1.代码是稳定的.即使经过严格测试,其暴露的BUG也是最少.一般来讲BUG分为两类,一类是语言级别的;另外一类是业务级别的.好的程序员,应该将语言级别的BUG控         制在:每100行 低于0.5 个BUG. 而业务级别的BUG却因人而异,应该尽量做到每100行代码 低于0.2个BUG.

      2.代码是容易维护的. 不然其他人来维护你的代码,就很容易出BUG. 要时刻想到这个问题,在做交叉Code Reivew 时,一定不要怕丢面子.有问题一定要立即修改.

         我们写的程序要尽量满足OOP的开-闭原则,为什么是尽量呢,因为很多时候我们都是在维护别人写的代码,以及添加新功能,要去揣摩别人的思维是很困难的,如果再

         加上那位同事又离职的话,就更恼火了.因此,如果大家都是按照开-闭原则来设计程序的话,即使有人离开,那么他的代码也是容易维护的.由于开-闭原则强调对修改

         封闭,对扩展开放;这样当我们去维护别人的代码时,就很容易把BUG的出现控制在我们已知的范围内(新写的代码),而由于我们对以前的代码修改很少,这样在无形中

         我们就避免了很多BUG的出现.很多时候,程序中的BUG都是因为对原有代码的修改造成的.

以上的两点,都是我这几年的总结,都是血与泪的体验,期间也出了很多的BUG.虽然我们程序员都很讨厌BUG,但它总是在我们周围阴魂不散.但正是因为它的存在,才促使我们对于如何才能编写高质量代码的思考.

      后续,我会陆续分享我的一些想法,希望大家指正.

posted @ 2010-03-08 12:40 畅想自由 阅读(209) 评论(0) 编辑
摘要: Do not make joke with me. 但生活常和我开玩笑,我并未如愿开始新的征程,也许是年龄大了?也许是不愿意太冒险。我还是留在了原地,还是.NET,有些事情估计不会发生改变,但另外一些事情,我要看着它慢慢改变。一切就从自己开始吧。阅读全文
posted @ 2010-02-22 22:08 畅想自由 阅读(47) 评论(0) 编辑
摘要: 由于职业规划的原因,估计以后会很少使用.NET了。这几年虽然也做了些J2EE应用,但大部分时间还是在使用.NET。感觉.NET在WEB应用方面还是和J2EE差距很大,特别这几年不知道微软在搞什么,有点说不清楚也看不到方向(微软一心去搞SL了,呵呵。);其实这几年J2EE的发展,特别是那几个WEB框架的持续更新,已经一改以往开发效率低下的弊病,将WEB应用的开发提升到了另一个高度。当然,话说回来,....阅读全文
posted @ 2010-01-06 22:56 畅想自由 阅读(39) 评论(0) 编辑
摘要: 我们经常使用字符串的Replace方法,很多时候代码顺手就写出来了,很少去注意潜在的问题.比如要把一个html文件的扩展名修改成txt文件,一般我们都会这样写: String s="test.html"; s.Replace(".html",".txt"); 这样写表面上看似乎没有太大问题,一般来说,在很长的时间里都不会出问题,因为我们的程序或者用户都是用小写字母来创建扩展名.但某天就有那么一个用...阅读全文
posted @ 2010-01-04 21:39 畅想自由 阅读(79) 评论(0) 编辑
摘要: 第一个JAVA WEB项目已经上线一段时间了,现把部署中的一些问题做个记录,希望能为遇到相同问题的其他朋友做个参考. 1.Tomcat 在本地没有任何问题,但部署到服务器后却死活无法启动. 查看Windows系统日志,几乎毫无帮助,尽是一些废话;Google了一哈,也毫无结果,因为日志里面的问题描述就不清楚. 后来发现原来是没有设置JAVA虚拟机的路径, 狂晕...,赶快设置后,Tomcat正常启...阅读全文
posted @ 2009-12-28 18:06 畅想自由 阅读(596) 评论(0) 编辑
摘要: 这一年,真不知道在混什么,所以最近一直在看这两本书: JAVA与模式,精通正则表达式。 很早就买了,但一直没有坚持看,我承认,我很后悔.。前一本让我熟悉了JAVA和自认为很熟悉的设计模式;后一本,让我意外的发现原来在PERL中使用正则表达式,是一件非常爽的事情,同时也感觉到PERL的强大: 语法精短,高效。阅读全文
posted @ 2009-12-26 17:22 畅想自由 阅读(14) 评论(0) 编辑