正態隨機數和 NaN 的極端情況
在嘗試實現我在 C++ 中模擬 SDE 的 Euler 方法版本時,我遇到了一個問題。在某些情況下,我的方法生成的路徑最終給出的值是
NaN
(非數字)。這種情況很少發生,但如果我計算 100 條路徑,通常會出現大約 1 或 2 種情況。我相信問題出在正常的隨機數上 $ Z_i $ 我用於迭代的
$$ S_{i+1}=S_i+f(S_i)\cdot \sqrt{dt}\cdot Z_i $$ (例如 SDE 是 $ dS_t=f(S_t)dW_t $ )。我嘗試使用
std::normal_distribution
生成器std::mt199737
並實現我自己的 Box-Muller 方法(使用 生成統一數字std::uniform_real_distribution
)。 使用這兩種方法,總是存在使整個模擬變為無窮大並產生 的奇數值NaN
。問題是我需要對最終值進行一些計算 $ S_1 $ 由我的路徑產生。我應該忽略
NaN
那些嗎?與路徑總數相比,它們的數量非常少。人們在執行這種類型的模擬時會遇到這些問題嗎?
這是我的程式碼:
#include <iostream> #include <vector> #include <random> typedef double ( *funct )( double ); double square( double x ) { return x * x; } double fourx( double x ) { return 4 * x; } double generateGaussian(); std::vector< double > createPath( unsigned, double, funct ); int main() { double initial = 1.0; unsigned intervals = 3000; unsigned paths = 500; std::vector< double > path; int n = 0; for ( auto j = 0; j < paths; ++j ) { path = createPath( intervals, initial, square ); if ( isnan( path.back() ) ) ++n; } std::cout << n << std::endl; } double generateGaussian() { static std::mt19937 generator( std::random_device{}() ); std::normal_distribution< double > dist( 0.0, 1.0 ); return dist( generator ); } std::vector< double > createPath( unsigned numberOfIntervals, double initialCondition, funct f ) { double sqdt = sqrt( 1.0 / numberOfIntervals ); std::vector< double > path; path.push_back( initialCondition ); for ( auto i = 0; i < numberOfIntervals; ++i ) { double Z = generateGaussian(); double Si = path.back(); double S = Si + f( Si ) * sqdt * Z; path.push_back( S ); } return path; }
我只是用它編譯它
g++ -std=c++11 test.cpp
這是在 Mac OS X 10.10.5 的終端上:
g++ -v Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 7.0.2 (clang-700.1.81) Target: x86_64-apple-darwin14.5.0 Thread model: posix
有時我會得到一條以
NaN
. 我還用其他功能實現了這一點,並得到了類似的情況。我嘗試例如服用 $ f(x)=4x $ (所以 $ dS_t=4S_tdW_t $ ),有時我會得到異常巨大的數字(甚至忽略NaN
路徑)。同樣在這種特殊情況下 $ f(x)=4x $ ,我從執行到執行得到完全不一致的結果,這讓我很惱火,但我還沒有想過為什麼。最後,如果我用 0 初始化生成器,我會得到完全相同的程式碼 2
NaN
。
問題不在於您的程式碼,而在於 SDE 本身。過程
$$ \begin{equation} \mathrm{d}S_t = \sigma S^\beta \mathrm{d}W_t \end{equation} $$ 是一個非負局部鞅。為了 $ \beta \leq 1 $ 它是鞅並且對於 $ \beta > 1 $ 這是一個嚴格的局部鞅。這體現在您的模擬中,當使用該函式時,某些路徑的擴散項會爆炸
square
。它導致S = Inf
orS = -Inf
和 下一步以及您獲得的所有後續步驟S = NaN
。使用您的功能
fourx
時,您不應該遇到這種情況。SDE 的更好離散化$$ \begin{equation} \mathrm{d}S_t = \sigma S_t \mathrm{d}W_t \end{equation} $$ 是通過模擬日誌。即你近似
$$ \begin{equation} \mathrm{d} \ln S_t = -\frac{1}{2} \sigma^2 \mathrm{d}t + \sigma \mathrm{d}W_t \end{equation} $$ 經過
$$ \begin{equation} \ln S_i = \ln S_{i - 1} - \frac{1}{2} \sigma^2 \Delta t + \sigma \sqrt{\Delta t} Z. \end{equation} $$ 這樣,您就擺脫了擴散係數中的狀態依賴性,並且對於任何步長都不會產生離散化誤差。
另請參閱此相關問題。