| 加入收藏| 设为首页| 联系我们

首页 站长学习 站长之家 源码下载 建站素材 书籍教程 常用工具
 您现在的位置: 动力中国 >> 网络编程 >> ASP.NET教程 >> 文章正文  
 [组图]完美解决.Net业务中的数值精度陷阱
 

完美解决.Net业务中的数值精度陷阱

http://www.domcn.org  文章来源:本站原创  点击数:

  关键字:完美解决.Net业务中的数值精度陷阱

        又是一阵痛和无奈的修改,公司业务系统数量小数位保留3位精度不够,需要保留6位才行,回想起这个问题,公司开发上线的ERP系统,数量,金额,成本的计算方式反反复复都修改过好多次,以前都没有对这个业务规则进行计算封装,和统一指定规则,修改就成了一件多而繁琐的的事情了;现在深刻体会这些业务细节将会对业务系统的运行和维护是非常重要的, 而业务系统规则的明晰和好的系统业务架构是对其的保证。    修改过程是一个渐进,琐碎的过程,希望有过次方面经验的朋友能提提建议,没有注意到这些细节的朋友少走弯路


修改过程是一个渐进的过程,希望有过次方面经验的朋友提提建议,也希望没有注意到这些细节的朋友少走弯路
 
简单归纳了下,产生问题的地方有3个方面:

第一个陷阱是计算精度丢失,有这几个原因引起的

1 查看后台代码的发现代码里有有变量是用的float或double类型,这样精度在计算的时候特别计算有乘除法的时候就会有精度转换误差,这个比较容易解决,都改为decimal 类型就可以了;
(我一时也没有找到合适的数据,如果找到数据的话,会加上这段demo):


2 是发现有很多计算的精度丢失是因为使用到中间变量的原因,而在中间变量有保留小数位!
现在修改方式第一种方式是中间变量的精度尽可能长,第二方式是直接用原始变量来计算最终结果

3 有部分计算是js来计算的,因为js里没有decimal类型的变量,这种常常会产生精度丢失,需要最后ToFix()下保留精度,这也使得在页面上显示的结果,需要指定精度。


第二个陷阱是 存储的数值的精度丢失,是因为数字类型未设置正确, 如设置成float ,double 类型都可能有转换精度丢失,decimal类型没有暂时没有在系统中使用过。也有种情况是中间小数位精度不够长,数值如果用于再次计算的时候,也将出现精度不够的情况。我们现在一般都需要设置数字类型为numerice,数量保留6位小数,显示金额保留2位,计算成本保留8位小数

第三个陷阱是 显示数值,精度保留高了,新的矛盾又产生出来了,如果不加以转换直接显示出来,小数位就会有长串的小数位0跟在后面,但显示有些地方,需要显示小数位去除多余的0, 比如在是报表的显示,和页面显示比较拥挤的地方

在报表里最简便的方法是,利用公式字段去除显示多余的0

设置方法如下:

选择需要格式化的字段, 选“自定义样式”,在“四舍五入”里选择0.0001,然后点“十位”后面的按钮,输入以下公式:   
    
  if   Right   (ToText   ({命令_4.PartNum},   6),   6) =   000000   then   0   else   
  if   Right   (ToText   ({命令_4.PartNum},   6),   5) =   00000   then   1  else   
  if   Right   (ToText   ({命令_4.PartNum},   6),   4) =   0000   then   2  else  
  if   Right   (ToText   ({命令_4.PartNum},   6),   3)   =   000   then   3  else  
  if   Right   (ToText   ({命令_4.PartNum},   6),   2)   =   00   then  4   else  
  if   Right   (ToText   ({命令_4.PartNum},   6),   1)   =   0   then   5  else   6

可以实现数字保留6位精度,如果数值有0 的地方自动去除掉多余的0

设置步骤如下图(里面公式稍稍有不一样,但是都可以实现结果):







也可以用修改Sql的方式去除多余的小数位0

SELECT
col,
col_convert = CASE
WHEN CHARINDEX(., col) = 0
THEN col
WHEN RIGHT(col, PATINDEX(%[^0]%, REVERSE(col))) LIKE .%
THEN LEFT(col, LEN(col) - PATINDEX(%[^0]%, REVERSE(col)))
ELSE LEFT(col, LEN(col) - PATINDEX(%[^0]%, REVERSE(col)) + 1)
END
FROM(
SELECT col = 100 UNION ALL
SELECT col = NULL UNION ALL
SELECT col = .100 UNION ALL
SELECT col = .100100 UNION ALL
SELECT col = 0. UNION ALL
SELECT col = 0 UNION ALL
SELECT col = 100.1010 UNION ALL
SELECT col = 100.0000
)A

这点解决方法,参考于csdn对这个问题的讨论
http://community.csdn.net/Expert/topic/5766/5766540.xml?temp=.384289


最后总结下其他还可能出错的地方:

1很多数值不正确是因为计算公式或逻辑不明确引起的,有些代码是没有真正理解清楚就开始在开发了;ERP系统的开发对业务 的逻辑理解是非常重要的;

2 后台显示去除0的方法也有一种是,在程序里直接double.Parse()下就可以去除掉小数位多余的0,再ToString()为字符显示,double类型有个问题,如果数字为连续的5位小数0,就会显示为自动缩变为科学计算法,如果是后台显示的地方,可以先double.parse()下,转为string,再转为decimal类型就会去除掉多余的小数位0了。
demo代码如下: using System;

namespace Decimal_Round
{
    /**//// <summary>
    /// Class1 的摘要说明。
    /// </summary>
    class Class1
    {
        /**//// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            decimal decQty = decimal.Parse(0.000001) ;
            Console.WriteLine({0},decQty);

            float fQty =  float.Parse( 0.000001 ) ;
            Console.WriteLine({0},fQty);

            double dQty =  double.Parse(0.000001) ;
            Console.WriteLine({0},dQty);

            decQty = decimal.Parse(0.100000) ;
            Console.WriteLine({0},decQty);
 
            decQty=  decimal.Parse(double.Parse(0.100000).ToString()) ;//先double.parse()下,转为string,再转为decimal类型就会去除掉多余的小数位0了

            Console.WriteLine({0},decQty);

            Console.ReadLine();
        }
    }
}


3 最先我们把数量保留3位精度,金额保留2位,和成本保留4精度,后来发现实际业务计算的时候是不够的,应该早考虑这方面的业务规则定义和计算,可以使用Excel或类似的工具来早与客户,架构师,程序员,测试员之间沟通;

4 使用到业务类方法进行计算的地方,需要注意构造接口参数的正确性

5 需要有足够全面的测试用例进行测试,同时也注意容错性测试;

在js,后台程序,数据库,报表都需要一系列的规则来对这些业务规则进行封装,最终的想法是通过数据库或配置文件来实现自动选择配置,我打算稍后的文章将详细总结下这方面的架构和思路


完美解决.Net业务中的数值精度陷阱
  • 上一篇文章:

  • 下一篇文章:
  •  热门文章
    普通文章 电子邮件改头换面 四公司畅谈未
    普通文章 PC病毒史上最声名狼藉的八大病
    普通文章 Rails系统中的AJAX开发技术简析
    普通文章 基于ASP.NET AJAX框架实现表单
    普通文章 开发ASP.NET AJAX客户端定制行
    普通文章 用JFreeChart对JSP报表进行增强
    普通文章 SQL Server 2005上的CLR和ADO.
    普通文章 SQL Server 2005的XML支持机制
    普通文章 Firefox中标签式浏览技巧大全
    普通文章 Tomcat中的Session和Cookie大揭
     
     推荐文章
    推荐文章 把Google地图嵌入网页 就是这么
    推荐文章 迅雷搜索候选资源出错的解决
    推荐文章 轻松去除迅雷里的各种广告和资
    推荐文章 突破限制 免费领养到QQ空间五级
    推荐文章 Rational统一过程RUP贴近中小软
    推荐文章 构建自己的轻量级XML DOM分析程
    推荐文章 WPS Office 2007技巧:妙用配置
    推荐文章 Excel 2007:求余数函数实用进阶
    推荐文章 浅谈ASP.NET的Postback
    推荐文章 软件开发中项目需求管理简述
     
     相关文章
    没有相关文章
    设为首页 | 加入收藏 | 广告合作 | 联系站长 | 版权申明 |
    动力中国为网友提供免费学习资料,可用资源,如果您认为我们的相关内容侵害到了您的权利请联系管理员
    Copyright © 2006-2008 domcn.org All Rights Reserved.