施藝
(四川省成都水文水資源勘測(cè)局,成都,611130)
水文數(shù)據(jù)是國(guó)家重要的基礎(chǔ)信息資源,而水文工作則是行業(yè)基礎(chǔ)數(shù)據(jù)的主要來源。為保證水文資料成果質(zhì)量,《水文資料整編規(guī)范》(SL/T 247-2012)對(duì)水文數(shù)據(jù)中各項(xiàng)要素計(jì)算、取用精度做出了要求:各項(xiàng)要素?cái)?shù)值應(yīng)按規(guī)范要求的取用精度取位,取用精度位數(shù)后一位數(shù)字,采用“四舍六入”方法取舍。為更好地適應(yīng)水文信息化和現(xiàn)代化發(fā)展,本文對(duì)水文數(shù)據(jù)的收舍以及在編程中的實(shí)現(xiàn)進(jìn)行了分析探討。
有效數(shù)字(Significant Figure),是在整個(gè)計(jì)算過程中大致維持重要性的近似規(guī)則。對(duì)于一個(gè)近似數(shù),從左邊第一個(gè)非零數(shù)字起,到精確到的位數(shù)止,所有的數(shù)字都叫作這個(gè)數(shù)的有效數(shù)字。簡(jiǎn)單地說,把一個(gè)數(shù)字前面的0都去掉,從第一個(gè)正整數(shù)到精確的數(shù)為止所有的數(shù)字都是有效數(shù)字。
在水文數(shù)據(jù)中,各項(xiàng)要素?cái)?shù)值的取用精度多采用“有效數(shù)字+小數(shù)不過多少位”的方式進(jìn)行取位,如流量、比降、輸沙率采用“3位有效數(shù)字,小數(shù)不過3位”,洪水量、徑流量采用“4位有效數(shù)字,小數(shù)不過4位”。取用精度位數(shù)后一位數(shù)字,采用“四舍六入”方法取舍。
四舍六入,全稱四舍六入五成雙,是一種比較精確、比較科學(xué)的計(jì)數(shù)保留法。具體規(guī)則為取用精度位數(shù)后1位小數(shù)小于5則舍,大于5則入,等于5時(shí)若其后有非零位數(shù)仍入,無非零尾數(shù)則視取用的末位數(shù)字的奇偶取舍,為奇則入,為偶則舍。
在國(guó)外,四舍六入又被稱為Banker's round(即銀行家舍入),大部分的編程軟件都使用的是這種方法,但具體到大家日常使用的辦公軟件卻很少使用四舍六入,基本都是四舍五入。比如EXCEL里的Round函數(shù)采用的是四舍五入,而VBA中的Round函數(shù)則采用的是四舍六入。
前文提到,日常使用的辦公軟件如OFFICE、WPS等基本都是采用四舍五入,無法滿足水文數(shù)據(jù)的收舍要求。如在EXCEL中,Round函數(shù)采用的是四舍五入,如果想要四舍六入,需要通過設(shè)置復(fù)雜的公式,即便通過公式能達(dá)到目的,也需要針對(duì)性地設(shè)置數(shù)值相應(yīng)的收舍位數(shù),對(duì)每個(gè)值進(jìn)行單獨(dú)設(shè)置,工作量很大,也很繁瑣。在編程中實(shí)現(xiàn)水文數(shù)據(jù)的收舍,既能為進(jìn)一步開發(fā)水文相關(guān)的軟件提供支撐,同樣也能通過與現(xiàn)有辦公軟件相結(jié)合,擴(kuò)展現(xiàn)有辦公軟件的使用局限,方便普通職工的使用。
限于會(huì)占用大量篇幅,文章只采用了一到兩種語言來進(jìn)行介紹,雖然不同語言的代碼格式不同,但思路是通用的。
3.2.1 有效數(shù)字的實(shí)現(xiàn)
在常用的編程語言中,除C++不支持Banker's round(即四舍六入)外,其余常用的編程語言都使用四舍六入。按有效數(shù)字進(jìn)行收舍則只有C++可以通過setprecision函數(shù)以及R語言可以通過signif函數(shù)可以做到。要按有效數(shù)字進(jìn)行四舍六入,可以通過封裝自定義函數(shù)來實(shí)現(xiàn)。
實(shí)現(xiàn)思路為:設(shè)數(shù)值為i,有效數(shù)字為d,數(shù)值的位數(shù)為k。先判斷數(shù)值i的位數(shù)k,大于1時(shí)k為正,取i整數(shù)部分位數(shù);小于1時(shí)k為負(fù),取i小數(shù)點(diǎn)后出現(xiàn)多少個(gè)連續(xù)的零。d減去k,得到需要收舍的位數(shù)n。按round(i,n)對(duì)數(shù)值i進(jìn)行四舍六入。
遇到的問題1:n為負(fù)時(shí)round函數(shù)無法工作,即收舍只能對(duì)數(shù)值的小數(shù)部分進(jìn)行收舍,無法根據(jù)有效數(shù)字對(duì)整數(shù)部分進(jìn)行收舍,如12850的3位有效數(shù)字應(yīng)收舍為12800。解決方案:對(duì)數(shù)值乘以10的n次方,然后按取整進(jìn)行四舍六入,再除以10的n次方,這樣就能對(duì)整數(shù)部分也進(jìn)行有效數(shù)字的收舍了。
遇到的問題2:判斷數(shù)值i的位數(shù)k,開始是用字符串進(jìn)行處理,方法為如果i大于1,取i小數(shù)點(diǎn)左邊的字符串的長(zhǎng)度;如果i小于1,取i小數(shù)點(diǎn)右邊數(shù)值的長(zhǎng)度減去i小數(shù)點(diǎn)右邊字符串的長(zhǎng)度。如0.0012小數(shù)點(diǎn)右邊字符串為0012、字符串長(zhǎng)度為4,而0012的值為12、字符串長(zhǎng)度為2,2減去4就得出i的位數(shù)k為-2。但這樣處理代碼效率不高,影響大量數(shù)據(jù)處理的效率。解決方案:經(jīng)過翻閱資料,發(fā)現(xiàn)一個(gè)小技巧,通過對(duì)數(shù)值(絕對(duì)值)求其以10為底的對(duì)數(shù),可以很方便地知道它的位數(shù)。如log10(0.0012)等于-2.9,向上取整后即為數(shù)值i的位數(shù)-2,log10(6554)等于3.8,向上取整后即為數(shù)值i的位數(shù)4。
以Java語言為例,實(shí)現(xiàn)代碼如下。
為方便普通職工在EXCEL中直接使用該函數(shù),接下來采用VBA語言進(jìn)行編譯,將函數(shù)封裝為自定義公式,實(shí)現(xiàn)代碼如下。
采用VBA語言進(jìn)行編譯需要注意的是:①EXCEL中默認(rèn)采用的是浮點(diǎn)數(shù)運(yùn)算,由于計(jì)算機(jī)在處理數(shù)據(jù)時(shí)存在二進(jìn)制與十進(jìn)制的轉(zhuǎn)換,直接對(duì)數(shù)值進(jìn)行處理往往會(huì)出錯(cuò),需要通過CDec函數(shù)將數(shù)值轉(zhuǎn)換為Decimal類型數(shù)據(jù)再進(jìn)行處理;②VBA中沒有l(wèi)og10函數(shù),也沒有向上取整,我們通過Log(i)/Log(10)來代替log10函數(shù),再通過Int(i)+1計(jì)算得到位數(shù)。
3.2.2 水文數(shù)據(jù)收舍的實(shí)現(xiàn)
水文數(shù)據(jù)的收舍,不僅需要滿足按有效數(shù)字進(jìn)行四舍六入,還要按不超過多少位小數(shù)進(jìn)行收舍。因此,還需要對(duì)自定義函數(shù)進(jìn)行加工。
實(shí)現(xiàn)思路為:設(shè)置可選項(xiàng)最大小數(shù)位數(shù)d1,默認(rèn)為0(不設(shè)置最大小數(shù)位數(shù)),可選項(xiàng)有效數(shù)字d2,默認(rèn)為0(不設(shè)置有效數(shù)字)。當(dāng)有效數(shù)字大于0,如果最大小數(shù)位數(shù)d1不小于有效數(shù)字d2減去數(shù)值i的位數(shù)k,需要收舍的位數(shù)n則為d2減去k,否則n等于最大小數(shù)位數(shù)d1。其余步驟參考之前代碼。為方便在其他代碼中調(diào)用該函數(shù)(下文會(huì)有介紹),可以設(shè)置全局變量Ⅳalue、iDigits,將收舍后的值賦予Ⅳalue、收舍的位數(shù)賦予iDigits。
以VBA語言為例,實(shí)現(xiàn)代碼如下。
3.3.1 復(fù)合條件的應(yīng)用
在水文數(shù)據(jù)的計(jì)算中,除了按有效數(shù)字以及最大小數(shù)位數(shù)進(jìn)行四舍六入,某些要素?cái)?shù)值是通過復(fù)合條件確定取用精度。比如流速為數(shù)值不小于1取3位有效數(shù)字,小于1取2位有效數(shù)字,小數(shù)不過3位;水深為數(shù)值不小于100記至1,小于100不小于5記至0.1,小于5記至0.01。針對(duì)這樣的情況,可以對(duì)自定義函數(shù)進(jìn)行再開發(fā),通過設(shè)定具體的要素類型,對(duì)數(shù)值進(jìn)行處理。接下來的代碼演示以下5種類型的取用精度及運(yùn)算。
類型1:取3位有效數(shù)字,小數(shù)不過3位。如流量、徑流模數(shù)、輸沙率等。
類型2:取3位有效數(shù)字,小數(shù)不過2位。如斷面面積、流量系數(shù)等。
類型3:不小于1,取3位有效數(shù)字;小于1,取2位有效數(shù)字,小數(shù)不過3位。如流速。
類型4:不小于100,記至1;小于100,不小于5,記至0.1;小于5,記至0.01。如水深。
類型5:取3位有效數(shù)字;不小于5,小數(shù)不過1位;小于5,小數(shù)不過2位。如水面寬、閘門開啟總寬、平均堰寬等。
3.3.2 按刊印要求進(jìn)行設(shè)置
在水文資料整編中,除了對(duì)數(shù)值的精度有要求,對(duì)數(shù)據(jù)的刊印格式也有同樣的要求,通過調(diào)用自定義函數(shù)可以方便我們對(duì)數(shù)據(jù)進(jìn)行處理。以下代碼用于在表格保存時(shí)對(duì)表格中的數(shù)值按刊印要求進(jìn)行位數(shù)的設(shè)置。
代碼解析:首先,將有數(shù)字的單元格設(shè)置為一個(gè)Range對(duì)象,遍歷這些單元格,根據(jù)單元格所在的位置將其設(shè)置為對(duì)應(yīng)的類型,比如表格中第三列是水深數(shù)據(jù)、第四列是面積、第五列是流速、第六列是流量,將第三列設(shè)為類型4、第四列設(shè)為類型2、第五列設(shè)為類型3、第六列設(shè)為類型1;其次,通過調(diào)用Sw_Round函數(shù),判斷數(shù)值是否滿足相應(yīng)類型的取用精度,不滿足則更改為收舍后滿足取用精度的值,比如流量10.25應(yīng)改為10.2;最后,根據(jù)Sw_Round函數(shù)得到的數(shù)值應(yīng)該保留的位數(shù),將其設(shè)置為對(duì)應(yīng)格式比如流速0.5應(yīng)寫為0.50。
本文簡(jiǎn)要介紹了通過程序語言封裝自定義函數(shù)實(shí)現(xiàn)水文數(shù)據(jù)的收舍,以及對(duì)相關(guān)函數(shù)的擴(kuò)展應(yīng)用,為進(jìn)一步開發(fā)水文相關(guān)軟件提供一定的支撐,同樣也能通過與現(xiàn)有辦公軟件相結(jié)合方便普通職工使用。以期解決以往遇到收舍與刊印要求時(shí)單個(gè)要求單個(gè)處理,缺乏可移植性,重復(fù)工作量大以及數(shù)據(jù)處理缺乏可靠性的問題。當(dāng)然,這只是筆者的一點(diǎn)經(jīng)驗(yàn)之談,旨在拋磚引玉,希望能讓更多的專業(yè)技術(shù)人員受到啟發(fā),將編程更多地應(yīng)用到水文信息化建設(shè)中。