今天财务告诉我线上有个¥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
据设定的哈希函数H(key)和所选中的处理冲突的方法,将一组关键字映象到一个有限的、地址连续的地址集(区间)上并以关键字在地址集中的“象”作为相应记录在表中的存储位置,这种表被称为哈希表.
鉴于C#的好书匮乏,建议朋友们在学习C#一段时间后,可以看看 Thinking in Java 这本书。其实这两种语言很多地方是相通的,应该不会感到太多的陌生。这本书对我的帮助就是,强化了我以前一直很匮乏的基础知识,这种知识,平时看不出有多么重要;因为只有在关键的时候,它才发挥巨大的作用。
编写.NET程序也有好几年了,一直在考虑如何才能编写高质量的代码,什么才算是高质量的代码呢? 我觉得至少要具备两个条件:
1.代码是稳定的.即使经过严格测试,其暴露的BUG也是最少.一般来讲BUG分为两类,一类是语言级别的;另外一类是业务级别的.好的程序员,应该将语言级别的BUG控 制在:每100行 低于0.5 个BUG. 而业务级别的BUG却因人而异,应该尽量做到每100行代码 低于0.2个BUG.
2.代码是容易维护的. 不然其他人来维护你的代码,就很容易出BUG. 要时刻想到这个问题,在做交叉Code Reivew 时,一定不要怕丢面子.有问题一定要立即修改.
我们写的程序要尽量满足OOP的开-闭原则,为什么是尽量呢,因为很多时候我们都是在维护别人写的代码,以及添加新功能,要去揣摩别人的思维是很困难的,如果再
加上那位同事又离职的话,就更恼火了.因此,如果大家都是按照开-闭原则来设计程序的话,即使有人离开,那么他的代码也是容易维护的.由于开-闭原则强调对修改
封闭,对扩展开放;这样当我们去维护别人的代码时,就很容易把BUG的出现控制在我们已知的范围内(新写的代码),而由于我们对以前的代码修改很少,这样在无形中
我们就避免了很多BUG的出现.很多时候,程序中的BUG都是因为对原有代码的修改造成的.
以上的两点,都是我这几年的总结,都是血与泪的体验,期间也出了很多的BUG.虽然我们程序员都很讨厌BUG,但它总是在我们周围阴魂不散.但正是因为它的存在,才促使我们对于如何才能编写高质量代码的思考.
后续,我会陆续分享我的一些想法,希望大家指正.