檢查策略

一個檢查策略控制一個區間類如何處理特殊情況,例如:空區間,無窮數, 非法值。

例如,讓我們考慮operator+(interval, T).第二個參數可以是一個非法值 (對於浮點數,它可以是 NaN). 在這種情況下,該怎麼辦呢,首先我們會說:第二個參數永遠都不會是非法值 ,其次,我們會說:這樣一種情況會發生但被禁止,第三,我們可以允許這種值,當遇到這種情況時,產生一個空區間.還有許多其它的可能性。

這就是為什麼使用一種檢查策略:有許多有趣的行為,武斷地選擇其中的一種將會是讓人不愉快的。

要求

檢查類應當滿足下面的要求(以接口的形式):

/* 檢查類的要求 */
struct checking
{
  static T pos_inf();
  static T neg_inf();
  static T nan();
  static bool is_nan(const T&);
  static T empty_lower();
  static T empty_upper();
  static bool is_empty(const T&, const T&);
};

開始的兩個函數, pos_infneg_inf, 會在每將類型需要創建無窮邊界區間時被調用 . 例如, interval::whole 計算 interval(checking::neg_inf(), checking::pos_inf()).計算 如果無窮邊界值被允許 ,並且,std::numeric_limits<T>::infinity() 返回一個正確的值,那麼將會使用這個值。

下一個是函數nan. 這個函數會在每一次函數需要返回一個T類型的值 ,但是不能計算這個值時使用,僅當函數的某一個參數非法的情況下才會發生,例如,如果你詢問一個空區間的中值是多少,將會調用函數nan,但請記住:lowerupper 直接返回區間中存儲的值,所以,如果區間為空,函數lowerupper不會通過調用checking::nan 來返回結果(並且會和checking::empty_lower返回值相同 ).

函數empty_lowerempty_upper 分別返回空區間的下邊界和上邊界. 與函數checking::nan相比,沒有要求函數empty_lowerempty_upper返回相同的值.例如,如果類型T沒有任何非法值, empty_函數可以返回區間[1,0].

函數is_nan用於測試T類型的一個值是否合法,函數is_empty用於測試由兩個參數構造的區間是否為空,這些測試通常會在那些涉及T類型的函數開始時調用,如果某一個參數聲明為非法的,那麼個函數將會試圖產生一個非法的值或是一個輸入區間。

概要

namespace boost {
namespace numeric {
namespace interval_lib {

template<class T>
struct checking_base;
template<class T, class Checking = checking_base<T>, class Exception = exception_create_empty<T> >
struct checking_no_empty;
template<class T, class Checking = checking_base<T> >
struct checking_no_nan;
template<class T, class Checking = checking_base<T>, class Exception = exception_invalid_number<T> >
struct checking_catch_nan;

template<class T> struct exception_create_empty { T operator()(); };
template<class T> struct exception_invalid_number { void operator()(); };

} // namespace numeric
} // namespace interval_lib
} // namespace boost

預定義的類

為了簡化策略的定制,類庫中已經定義了一些模板.

首先,有一個 checking_base類. 得益於std::numeric_limits<T>提供的信息,這個類可以為策略類生成一個基類,如果類型T暗含NaNs(由numeric_limits::has_quiet_NaN所描述的), 那麼這個值由函數nan, empty_lower, empty_upper使用,以及一個用於函數is_nan的基本測試(也就是: x!=x)。 如果T類型沒有暗含NaNs,那麼一個函數is_nan是一個assert(false)斷言, 空區間是[1,0], 並且函數is_nan永遠返回false。像函數nan一樣, 函數pos_inf返回numeric_limits::infinity()。如果可能的話, 或者是一個assert(false)斷言. 函數neg_inf返回相反的結果,最後,is_empty(T l,T u) 永遠通過!(l<=u)來定義.

接下來的是checking_no_empty類. 使用這個類意味著每一次將會產生一個空的區間(通過empty_lowerempty_upper), 這個由模板的異常參數Exception指定的函數對像會被調用,並且其返回值將被傳播.所以,如果異常Exception被合適的定義(例如: 它可以拋出一個異常, 也就是參數的名字所指定的異常), 你可以確信永遠都不會有空區間產生,因此,函數is_empty 永遠都返回false (因沒有必要測試空區間). 就像前面解釋的那樣,我們同樣可以使用assert(false)斷言來來替換NaN; 你可以確信永遠都不會產生非法值,如果沒有使用這個模板,那就暗含著所有的函數都可以產生空區間,並且它們可以正確處理這些空區間參數 .

最後, checking_no_nan類和checking_catch_nan類. 第一個類表明庫中的函數永遠都不會接收非法值作為參數. 所以,函數is_nan將返回false. 另一個函數意味著參數可能是非法值, 函數is_nan將會調用函數對像Exception 並且返回 false.實際上,這個模板意味著非法數字永遠都不會進入到函數體中,如果這兩個模板都沒被使用,那暗含著所有的函數都可能接收非法值並且它們可以正確處理這些非法值。

exception_create_empty拋出std::runtime_error異常,異常消息為:"boost::interval: empty interval created"exception_invalid_number 拋出std::invalid_argument異常,異常消息為:"boost::interval: invalid number".

定制你自己的檢查策略

為了定義一個合適的策略,你需要正確地描述你想從區間類中得到什麼,首先,你是否在意在計算的最後得到一個空的區間, 如果你不想得到空的區間,函數empty_lower和函數empty_upper在調用時應當調用失敗(它們可以拋出異常,設置一個標記).然而,如果沒有函數會產生空區間,也就沒有必要進行這些測試,因此,函數is_empty永遠都返回false.在這種情況下,一個好的編譯器將會進行大量的優化.

你也可能會對計算的最後產生的空區間有興趣,例如,如果你需要把轉換一個數組的不確定值(或區間)轉換到一個新的區間數組中, 你可能不想在遇到第一個問題時就停下來,那麼函數empty_lower和函數empty_upper需要返回合適的值用來定義一個空的區間(你可以使用一個上邊界小於下邊界的值);並且 函數is_empty應當可以從合法的區間中區分出空區間.

另一個重要的問題是:是否可能有一些基數字(base numbers) (T類型的對象) 是合法的? 如果可能,它們是否被允許,如果不可能,就沒有測試的必要了,函數is_nan永遠返回 false.也是在這種情況下,好的編譯器可以進行大量的優化,如果函數參數可能保存非法值,依據非法值是否被允許,有兩種情況需要考慮,如果允許,函數is_nan就必須測試它們是否是合法的,如果禁止,當使用非法的參數調用函數is_nan時,應當調用失敗(產生異常或失敗斷言)並且返回false. 函數nan返回值沒什麼神奇的地方,因為區間函數保證不會返回非法的區間邊界值,除非用戶向構造函數傳遞了非法值。 所以,如果你不信任這個庫,你可以在函數體內放置一個斷言:-)

最後,如果在最開始的時候沒有決定,你需要決定如何處理函數nan以及函數pos_inf和函數neg_inf,這些函數應當返回合法值或是拋出一個異常(尤其是如果基類型沒有對應的值 ).

一些例子

Valid HTML 4.01 Transitional

Revised 2006-12-24

Copyright © 2002 Guillaume Melquiond, Sylvain Pion, Hervé Brönnimann, Polytechnic University
Copyright © 2003-2004 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)