Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

改變缺省策略(Changing the Policy Defaults)

這個庫所使用的缺省策略通過使用配置宏(configuration macro)來改變。

例如,將-DBOOST_MATH_DOMAIN_ERROR_POLICY=errno_on_error 傳遞給你的編譯器將會在出現定義域錯誤時設置::errno 並返回 NaN 而不是通常的缺省拋出異常std::domain_error

[Tip] 提示

對於 Microsoft Visual Studio,你可以在 Project Property Page, C/C++, Preprocessor, Preprocessor 進行如下定義:

BOOST_MATH_ASSERT_UNDEFINED_POLICY=0
BOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error

這可能對避免與預編譯頭文件(pre-compiled headers)可能意味著與下面的的代碼等價的複雜性:

#define BOOST_MATH_ASSERT_UNDEFINED_POLICY false
#define BOOST_MATH_OVERFLOW_ERROR_POLICY errno_on_error

可能會被忽略。

編譯器命令行顯示:

/D "BOOST_MATH_ASSERT_UNDEFINED_POLICY=0"
/D "BOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error"

對於這一點有一個非常的重要的警告:

[Important] 重要

通過設置配置宏來改變缺省策略必須在這個程序中的每個編譯單元中一致地改變。(Default policies changed by setting configuration macros must be changed uniformly in every translation unit in the program).

沒有遵守這個規則可能導致違反「One Definition Rule(ODR)」並導致不可預測的程序結果。

這就意味著只有兩種使用這些宏的安全方式:

不應該 做的是:

是的,你將會在我們的例子程序中發現我們將會破壞這個規則:這是因為我們知道這個例子程序只會有一個編譯單元(translation unit):不要說你沒有被提醒過!

下面的例子程序顯示了當遇到一個非法參數的時候,使用 BOOST_MATH_DOMAIN_ERROR_POLICY 。出於這個程序的目的,我們將一個負的自由度(degree of freedom)傳遞給一個學生t分佈(Student's t Distribution)。

因為我們知道這是一個單文件的程序,所以我們可以簡單地添加:

#define BOOST_MATH_DOMAIN_ERROR_POLICY ignore_error

來改變缺省的策略,使得在遇到定義域錯誤的時候返回NaN,另一方面我們可以使用:

#define BOOST_MATH_DOMAIN_ERROR_POLICY errno_on_error

來確保當遇到定義域錯誤時設置::errno 並返回NaN。

這只在假定程序只有一個編譯單元(translation unit)並且我們在任何的#include之前使用#define的時候這種做法才是安全的。注意:如果我們把#define放在#include後面的時候就不會有任何作用!一個類似於下面的warning

warning C4005: 'BOOST_MATH_OVERFLOW_ERROR_POLICY' : macro redefinition

是不會產生預期結果的肯定提示。

我們將包含一些需要的頭文件:

// Boost
#include <boost/math/distributions/students_t.hpp>
   using boost::math::students_t;  // Probability of students_t(df, t).

// std
#include <iostream>
   using std::cout;
   using std::endl;

#include <stdexcept>
   using std::exception;

接下來,我們定義程序的main()比函數來使用非法的自由度參數調用學生t分佈(Student's t Distribution)。這個程序被設置為處理異常或返回NaN:

int main()
{
   cout << "Example error handling using Student's t function. " << endl;
   cout << "BOOST_MATH_DOMAIN_ERROR_POLICY is set to: "
      << BOOST_STRINGIZE(BOOST_MATH_DOMAIN_ERROR_POLICY) << endl;

   double degrees_of_freedom = -1; // A bad argument!
   double t = 10;

   try
   {
      errno = 0;
      students_t dist(degrees_of_freedom); // 如果如果的話,這裡會拋出異常
      double p = cdf(dist, t);
      // 測試其它的方式報告錯誤:
      if((boost::math::isnan)(p))
      {
         cout << "cdf returned a NaN!" << endl;
         cout << "errno is set to: " << errno << endl;
      }
      else
         cout << "Probability of Student's t is " << p << endl;
   }
   catch(const std::exception& e)
   {
      std::cout <<
         "\n""Message from thrown exception was:\n   " << e.what() << std::endl;
   }

   return 0;
} // int main()

下面是使用缺省的編譯選項時的程序的輸出(確實拋出了異常):

Example error handling using Student's t function.
BOOST_MATH_DOMAIN_ERROR_POLICY is set to: throw_on_error

Message from thrown exception was:
   Error in function boost::math::students_t_distribution<double>::students_t_distribution:
   Degrees of freedom argument is -1, but must be > 0 !

另一方面,讓我們使用下面的編譯選項來編譯:

#define BOOST_MATH_DOMAIN_ERROR_POLICY ignore_error

現在程序的輸出為:

Example error handling using Student's t function.
BOOST_MATH_DOMAIN_ERROR_POLICY is set to: ignore_error
cdf returned a NaN!
errno is set to: 0

最後讓我們使用下面的編譯選項來編譯:

#define BOOST_MATH_DOMAIN_ERROR_POLICY errno_on_error

程序輸出為:

Example error handling using Student's t function.
BOOST_MATH_DOMAIN_ERROR_POLICY is set to: errno_on_error
cdf returned a NaN!
errno is set to: 33


PrevUpHomeNext