当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > .Net业务平台的数值精度陷阱与解决方法

ASP.NET
FreeTextBox(版本3.1.6)在ASP.Net 2.0中使用方法
.NET 常用功能和代码小结
在 .NET Framework 2.0 中未处理的异常导致基于 ASP.NET 的应用程序意外退出
asp.net IList查询数据后格式化数据再绑定控件
asp.net sql存储过程
asp.net 简单实现禁用或启用页面中的某一类型的控件
asp.net(c#)获取内容第一张图片地址的函数
The remote procedure call failed and did not execute的解决办法
ASP.NET 在线文件管理
asp.net 读取并修改config文件实现代码
ASP.NET Cookie 操作实现
asp.net Silverlight中的模式窗体
Silverlight中动态获取Web Service地址
asp.net Silverlight应用程序中获取载体aspx页面参数
asp.net 水晶报表隔行换色实现方法
asp.net 获取Gridview隐藏列的值
手动把asp.net的类生成dll文件的方法
asp.net 使用ObjectDataSource控件在ASP.NET中实现Ajax真分页
动态指定任意类型的ObjectDataSource对象的查询参数
asp.net Md5的用法小结

ASP.NET 中的 .Net业务平台的数值精度陷阱与解决方法


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-08-14   浏览: 69 ::
收藏到网摘: n/a

本文主要介绍一下.Net业务平台的数值精度陷阱与解决方法。

最近公司的实施人员反映,数量小数位保留3位精度不够,需要保留6位才行,回想起这个问题,公司开发上线的ERP系统,数量,金额,成本的计算方式反反复复都修改过好多次,以前都没有对这个业务规则进行计算封装,和统一指定规则,修改就成了一件多而繁琐的的事情了;现在深刻体会这些业务细节将会对业务系统的运行是非常重要的,而业务系统规则的明晰和好的系统业务架构是对其的保证。

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

最先意识到的是计算精度丢失,主要是这几个原因引起的:

1、查看后台代码的发现代码里有有变量是用的float或double类型,这样精度在计算的时候就会有精度转换误差,这个比较容易解决,都改为decimal 类型就可以了;

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

3、有部分计算是js来计算的,因为js里没有decimal类型的变量,这种常常会产生精度丢失,需要最后ToFix()下保留精度。

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

第三方面是显示的问题,在某些特定的地方,需要显示小数位去除多余的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

可以简单对这个sql封装成函数来实现;

最后还值得注意的有3点:

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

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

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