這個例子演示如何設計一個參數為一個多項式和一個數值的函數,返回這個多項式在這個數值點上的符號. 這個函數是一個過濾器,如果結果是不受保證的,這個函數會指明這一點,使用個過濾器而不使用一個求值函數的理由在於,浮點數的運算將會產生近似值, 因此為了 使結果生效,這個函數使用區間算術.
第一步是包含合適的頭文件,因為這個函數會處理浮點範圍,最簡單的解決方法是:
#include <boost/numeric/interval.hpp>
現在讓我們開始設計這個函數,多項式由一組它的係數和它的大小來指定( 嚴格大於它的度數(degree) ). 為了簡化代碼,引入庫中的兩個名字空間
int sign_polynomial(double x, double P[], int sz) {
using namespace boost::numeric;
using namespace interval_lib;
然後我們可以定義區間的類型,因為沒有特殊行為要求,默認的策略就足夠了:
typedef interval<double> I;
對於求值, 我們使用霍納法則(Horner scheme)來進行區間算術。這個庫重載了所有的算術運算符並提供混合運算,所以,代碼中有沒有區間算術依賴於迭代值y的類型
:
I y = P[sz - 1];
for(int i = sz - 2; i >= 0; i--)
y = y * x + P[i];
最後一步是計算y的符號,通過選擇合適的比較訪求來完成,然後使用通常的運算符來進行比較:
using namespace compare::certain; if (y > 0.) return 1; if (y < 0.) return -1; return 0; }
結果為0 並不意味著多項式的結果0.它只意味著答案無法知道,因為包含0,因此沒有一個精確的符號.
現在我們有了一個預期的函數,然而,由於大多數的處理器中簡陋的浮點捨入實現,優化代碼是很有用的,或者直接讓庫來優化代碼 對於 這種優化,最主要的情況是區間代碼不應當和浮點運算代碼在一起混合使用,在這個例子中, 剛好就是這種情況,函數中完成的所有的操作涉及到這個庫,因此代碼可被重寫為:
int sign_polynomial(double x, double P[], int sz) {
using namespace boost::numeric;
using namespace interval_lib;
typedef interval<double> I_aux;
I_aux::traits_type::rounding rnd;
typedef unprotect<I_aux>::type I;
I y = P[sz - 1];
for(int i = sz - 2; i >= 0; i--)
y = y * x + P[i];
using namespace compare::certain;
if (y > 0.) return 1;
if (y < 0.) return -1;
return 0;
}
這些代碼和前面代碼的區別在於使用了另一個區間類型,新的類型T指示這個庫所有的運算可以在不關心捨入方式的情況下完成,因為這一點,由函數來關注這一點,無論何時使用優化類型,都應當存在一個捨入對像.
libs/numeric/interval/test/ 和
libs/numeric/interval/examples/ 是一些測試和例子程序,舉例說明區間的一些使用方法,對於使用這個庫的更通用的描述和考慮以及一些潛在的應用領域請閱讀mini-guide.
測試程序如下:請注意它們需要使用 Boost.test 庫,通過使用bjam來自動完成測試( 除了 interval_test.cpp).
add.cpp測試加法和減法運算符,以及相應的_std 和_opp捨入函數正確實現. 通過使用符號表達式作為基類型來完成 .
cmp.cpp, cmp_lex.cpp, cmp_set.cpp, 和
cmp_tribool.cpp測試運算符<
> <= >= ==
!=對於默認的 字典序, 集合, 以及
三態比較都能正常運行.
cmp_exp.cpp 測試明確的比較函數cer..和pos..正常運行.
cmp_exn.cpp 測試各種策略是否偵測到各種異常情況, 所有的這些測試使用簡單的區間
([1,2] and
[3,4], [1,3] and [2,4], [1,2] and [2,3], etc).
det.cpp測試_std 和 _opp
在保護和無保護的模式下,當在一個不穩定矩陣上使用高斯範式的時候是否產生相同的結果(為了檢測捨入)這些測試針對於 interval<float> 和 interval<double>.
fmod.cpp 定義了一個 interval<int> 版本的 fmod 並且使用這個版本來針對特定的區間值進行測試
mul.cpp用一些產生精確值的整數區間練習乘法,有限除法,平方,平方根運算.
pi.cpp 測試區間值π (針對 int,
float 和 double基類型)是否包含數字π (具有21位有效數字)以及它是否是
[π±1ulp] 的子集 (為了確保精度).
pow.cpp測試在一些簡單的測試情況下pow是否運行正常
.
test_float.cpp測試這個區間針對於浮點基類型的算術運算.
interval_test.cpp 通過一些針對於double和interval<double>運算測試區間庫是否滿足區間運算的
包含性質.
filter.cpp 包含計算幾何中用於判斷行列式符號的過濾器 ,這個例子受到Interval arithmetic yields efficient dynamic filters for computational geometry by Brönnimann, Burnikel and Pion, 2001這篇文章的啟發.
findroot_demo.cpp通過使用二分法以及產生gnuplot data來查找函數中的0值。為了使例子能夠正常運行,處理器需要能夠正確處理元函數。
horner.cpp 是一個真正基本的例子,對於整個函數使用無保護的區間操作(這個函數使用霍納法則(Horner scheme)來計算一個多項式的值) .
io.cpp 演示針對於區間的輸入和輸出運算符,廣泛的多種可能性解釋了為什麼庫沒有實現IO運算符,它們留給用戶實現。.
newton-raphson.cppNewton-Raphson算法特別版本的實現.這個例子練習未受保護的完全除法(full division),集合運算和空區間.
transc.cpp 通過使用一個外部庫來實現捨入策略針對於double的超越部分(在這種情況下是GMP的子集MPFR).
Revised 2006-12-24
Copyright © 2002 Guillaume Melquiond, Sylvain Pion, Hervé
Brönnimann, Polytechnic University
Copyright © 2003 Guillaume Melquiond
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)