工农业生产中每项实践活动都离不开数学理论的指导,对数字的处理上,涉及到小数位数、有效数字位数、取大(小)、取整、四舍五入、科学记数等在数学理论中都有透彻的研究。但在水文行业上,为提高资料精度,规范对大部分数字提出了“四舍六入,逢五奇进偶舍”的处理要求,同时还限制了相应的有效数字位数,以及对不同数值范围内的数据又有不同的规定。而计算机科学是数学的派生物,数学处理中没有明确这一模式,那么计算机也就不能直接处理这样要求的数据。虽然任何一个软件开发工具都没有提供这样的函数体,但都给开发人员提供了自定义函数的空间,这无疑是计算机的科学性、先进性的体现。笔者通过摸索,比较成功地定义了一个函数过程,既简单又实用,可以将它直接应用到处理全部水文数据上,它一经调入内存,使用方法和效率同系统函数没有任何区别。
1 .函数过程设计思路
按照水文资料整编规范,对任一个数值X的处理都有2个约束参数:最多保留小数位数m和有效数字位数n,在尾数的取舍上遵从“四舍六入,逢五奇进偶舍”,按此可分三步来组织数据结构。
第一步:分析m和n的关系可以发现每个数值的不为0的整数位数同小数位数之和为该数的有效数字位数。只要|X|≥10m-n,处理后的小数位数就小于m,而有效数字位数满足为n位。于是可以运用压栈的方法对X每次前移一个小数点,直到|X|<10m-n。
第二步:按条件m实施舍入。不难看出它是“四舍五入”的一个特例,只有一种特殊情况“舍”,那就是数值X应保留部分末位为偶数,以后只有1位且恰好为“5”,主要工作就是判断唯一此种情况的发生,其他情况执行数学上的“四舍五入”(Round)即可满足要求。运用判断树详见图1。
![1433048803.gif](http://g.co188.com/img/topics/new_topics/images/blank.gif)
第三步:出栈恢复操作数X,返回函数值。
2 .函数体源程序
函数过程脚本提供如下(这是一段PowerScript代码,各种编程代码大同小异,稍作改动即可):
// **“四舍六入,逢五奇进偶舍”自定义函数过程 **
// 函数形式 jjos(x,m,n) ,返回值ret_jjos为 Decimal 型
// x为操作数值, m为最多保留小数位数,n为有效数字位数
// m、n皆为 Integer 型
// m = 0 表示取整数,n = 0 表示对有效数字无要求
Integer i = 0
Decimal ret_jjos,j =1
if x < 0 then j =-1 //j 用于记忆是正数还是负数
if n > 0 then
Do while Abs(x) >= 10^(n - m)
x = x/10 // 向前移动一个小数点
i = i + 1
loop
end if
if Int(x * 10^(m +1)) = x * 10^(m + 1) then
x= Round(x,m + 2)
ret_jjos = Dec(left(Right(String(x),3),1))
ifRight(String(x),2) = "50" and Int(ret_jjos/2) = ret_jjos/2 then
ret_jjos= Truncate(x,m)*10^I // 唯一此种情况舍
else
ret_jjos= Round(x,m)*10^I // 不是那种情况执行四舍五入
endif
else
ret_jjos = Round(x,m)*10^I //其它情况执行四舍五入
end if
if n > 0 then
ifInt(ret_jjos) >= 10^(n - 1) then
ret_jjos= Int(ret_jjos)
elseifAbs(ret_jjos) >= 1 then
ret_jjos= Dec(Left(String(Abs(ret_jjos)),n + 1))*j
endif
end if
Return ret_jjos // 返回处理结果
以上程序是在“取整(Int)”、“四舍五入(Round)”、“舍(Truncate)”等系统函数的基础上完成的,函数的型式及其每个参数需要用户在属性设置中定义和声明,故叫做自定义函数。定义成功后便可在程序设计中象系统函数那样引用了,例如对流量计算结果Q的处理引用为Q=(Q,3,3),即保留3位有效数字且小数位数不超过3位,jjos(98750,3,3)=98800,jjos(0.0225,3,3)=0.022 。
3 .几点应注意的问题
3.1 不能直接引用情况的处理
水文测验规范对不同类型的数据有不同的规定,有时还对同一数据不同范围规定不同处理要求,例如对流量计算表中测点水深H的处理,规范要求当H<5m时保留2位小数,当H≥5m时保留1位小数,而对有效数字位数不作要求,需要在编程过程中做如下判断处理:
if H < 4.995 then
H = jjos(H,2,0)
Else
H = jjos(H,1,0)
End if
特别要注意这里的临界值必须是4.995而不是5,因为按照“四舍六入”的原则,4.995已经是5.0,否则会将4.995<H<5范围的值错误处理为5.00。其它类似情况也要确定正确的临界值。
3.2 避免引用错误
该函数本身没有对x值和参数m、n作相应的合理性检查,误操作了非Decimal 型数据和因手误将m、n值置为负数或非整数都可能会产生系统错误或导致溢出错误。如果编程人员在调试程序时出现死锁,应首先想到是否有此类错误的发生。
4 .在水质监测成果管理系统中的应用举例
在工作实际中,由于水文资料的特殊性,以及规范要求的复杂性,给计算机处理这些数据带来困难,都需要编程人员不断发现规律和总结经验。这里给出笔者在“水质监测成果管理系统”开发中遇到的处理“四舍六入”数据较复杂的例子,就是水质特征值的年统计问题。如表1,是该系统所做的42项水质化验项目中部分统计结果。可以看到表1 水质特征值年统计表(部分)
沧州水环境监测中心分析室 2002年09月10日填报
站次 |
站名
|
统计项目
|
氰化物
|
砷化物
|
挥发酚
|
六价铬
|
汞
|
镉
|
铅
|
铜
|
铁
|
硫化物
|
氟化物
|
(毫克/升)
|
|||||||||||||
(28)
|
(29)
|
(30)
|
(31)
|
(32)
|
(33)
|
(34)
|
(35)
|
(36)
|
(37)
|
(38)
|
|||
4
|
窦庄子
|
样品总数 |
2
|
2
|
2
|
2
|
2
|
2
|
2
|
2
|
2
|
2
|
2
|
|
|
检出率(%) |
50.0
|
50.0
|
100
|
0
|
100
|
100
|
50.0
|
100
|
100
|
100
|
100
|
|
|
超标率(%) |
0
|
0
|
100
|
0
|
100
|
50.0
|
50.0
|
0
|
50.0
|
100
|
100
|
|
|
实测 最小值 |
<DL
|
<DL
|
0.06
|
<DL
|
0.00374
|
0.004
|
<DL
|
0.013
|
0.12
|
0.89
|
1.01
|
|
|
实测 最大值 |
0.011
|
0.019
|
0.034
|
<DL
|
0.00412
|
0.026
|
0.07
|
0.022
|
2.28
|
6.12
|
2.20
|
|
|
最大值超标倍数 |
|
|
5.8
|
|
40.2
|
4.2
|
0.4
|
|
3.6
|
29.6
|
1.2
|
|
|
最大值出现日期 |
2.2
|
2.2
|
2.2
|
2.2
|
2.2
|
2.2
|
5.5
|
2.2
|
5.5
|
2.2
|
2.2
|
|
|
年平均 |
0.006
|
0.010
|
0.020
|
0
|
0.00396
|
0.015
|
0.04
|
0.02
|
1.20
|
3.50
|
1.60
|
有2处分析计算结果涉及“四舍六入”的处理:超标倍数和年平均值。超标倍数很简单,按照水质评价要求保留1位小数,那么全部采用jjos(超标倍数,1,0)就可取得正确的计算结果。而年平均值的统计分析,规范对42项各有不同小数位数和有效数字位数要求,即m和n各有不同,并且随着监测精度的不断提高,规范还将会随之更新。因此,在编程时逐个设定m和n值不但繁锁而且会缩短系统的使用周期。采用的办法是:在数据库设计中,将各水质项目的m和n值作为水质评价标准基础表的2个表项,如表2,并为数据库管理人员提供能够修改维护它们的界面,这样就能在编程时将水质标准、评价方法、检出限、m和n值等一并读入内存,有效地正确统计分析每个项目,使这一复杂问题简单化。
序号
|
项目
|
水 质 标 准
|
单位
|
评价
吗?
|
检出
判断
|
有效
数字
|
小数
位数
|
检出限
|
|||||
Ⅰ类
|
Ⅱ类
|
Ⅲ类
|
Ⅳ类
|
Ⅴ类
|
|||||||||
22
|
氨氮 |
≤
|
0.5
|
0.5
|
0.5
|
1.0
|
1.5
|
mg/L
|
是
|
否
|
3
|
2
|
0.05
|
23
|
亚硝酸盐氮 |
≤
|
0.06
|
0.1
|
0.15
|
1.0
|
1.0
|