2 * Copyright 1993-2013 NVIDIA Corporation. All rights reserved.
4 * Please refer to the NVIDIA end user license agreement (EULA) associated
5 * with this source code for terms and conditions that govern your use of
6 * this software. Any use, reproduction, disclosure, or distribution of
7 * this software and related documentation outside the terms of the EULA
8 * is strictly prohibited.
14 ////////////////////////////////////////////////////////////////////////////////
15 // Global types and parameters
16 ////////////////////////////////////////////////////////////////////////////////
19 #include <helper_cuda.h>
21 #include "binomialOptions_common.h"
25 ////////////////////////////////////////////////////////////////////////////////
26 // Internal GPU-side constants and data structures
27 ////////////////////////////////////////////////////////////////////////////////
29 #define CACHE_DELTA (2 * TIME_STEPS)
30 #define CACHE_SIZE (256)
31 #define CACHE_STEP (CACHE_SIZE - CACHE_DELTA)
33 #if NUM_STEPS % CACHE_DELTA
37 //Preprocessed input option data
46 static __constant__ __TOptionData d_OptionData[MAX_OPTIONS];
47 static __device__ float d_CallValue[MAX_OPTIONS];
48 static __device__ real d_CallBuffer[MAX_OPTIONS * (NUM_STEPS + 16)];
52 ////////////////////////////////////////////////////////////////////////////////
53 // Overloaded shortcut functions for different precision modes
54 ////////////////////////////////////////////////////////////////////////////////
55 #ifndef DOUBLE_PRECISION
56 __device__ inline float expiryCallValue(float S, float X, float vDt, int i)
58 real d = S * expf(vDt * (2.0f * i - NUM_STEPS)) - X;
59 return (d > 0) ? d : 0;
62 __device__ inline double expiryCallValue(double S, double X, double vDt, int i)
64 double d = S * exp(vDt * (2.0 * i - NUM_STEPS)) - X;
65 return (d > 0) ? d : 0;
70 ////////////////////////////////////////////////////////////////////////////////
72 ////////////////////////////////////////////////////////////////////////////////
73 static __global__ void binomialOptionsKernel()
75 __shared__ real callA[CACHE_SIZE+1];
76 __shared__ real callB[CACHE_SIZE+1];
77 //Global memory frame for current option (thread block)
78 real *const d_Call = &d_CallBuffer[blockIdx.x * (NUM_STEPS + 16)];
80 const int tid = threadIdx.x;
81 const real S = d_OptionData[blockIdx.x].S;
82 const real X = d_OptionData[blockIdx.x].X;
83 const real vDt = d_OptionData[blockIdx.x].vDt;
84 const real puByDf = d_OptionData[blockIdx.x].puByDf;
85 const real pdByDf = d_OptionData[blockIdx.x].pdByDf;
87 //Compute values at expiry date
88 for (int i = tid; i <= NUM_STEPS; i += CACHE_SIZE)
90 d_Call[i] = expiryCallValue(S, X, vDt, i);
93 //Walk down binomial tree
94 //So double-buffer and synchronize to avoid read-after-write hazards.
95 for (int i = NUM_STEPS; i > 0; i -= CACHE_DELTA)
96 for (int c_base = 0; c_base < i; c_base += CACHE_STEP)
98 //Start and end positions within shared memory cache
99 int c_start = min(CACHE_SIZE - 1, i - c_base);
100 int c_end = c_start - CACHE_DELTA;
102 //Read data(with apron) to shared memory
107 callA[tid] = d_Call[c_base + tid];
110 //Calculations within shared memory
111 for (int k = c_start - 1; k >= c_end;)
113 //Compute discounted expected value
115 callB[tid] = puByDf * callA[tid + 1] + pdByDf * callA[tid];
118 //Compute discounted expected value
120 callA[tid] = puByDf * callB[tid + 1] + pdByDf * callB[tid];
124 //Flush shared memory cache
129 d_Call[c_base + tid] = callA[tid];
133 //Write the value at the top of the tree to destination buffer
134 if (threadIdx.x == 0)
136 d_CallValue[blockIdx.x] = (float)callA[0];
142 ////////////////////////////////////////////////////////////////////////////////
143 // Host-side interface to GPU binomialOptions
144 ////////////////////////////////////////////////////////////////////////////////
145 static void binomialOptionsGPU(
147 TOptionData *optionData,
151 __TOptionData h_OptionData[MAX_OPTIONS];
153 for (int i = 0; i < optN; i++)
155 const double T = optionData[i].T;
156 const double R = optionData[i].R;
157 const double V = optionData[i].V;
159 const double dt = T / (double)NUM_STEPS;
160 const double vDt = V * sqrt(dt);
161 const double rDt = R * dt;
162 //Per-step interest and discount factors
163 const double If = exp(rDt);
164 const double Df = exp(-rDt);
165 //Values and pseudoprobabilities of upward and downward moves
166 const double u = exp(vDt);
167 const double d = exp(-vDt);
168 const double pu = (If - d) / (u - d);
169 const double pd = 1.0 - pu;
170 const double puByDf = pu * Df;
171 const double pdByDf = pd * Df;
173 h_OptionData[i].S = (real)optionData[i].S;
174 h_OptionData[i].X = (real)optionData[i].X;
175 h_OptionData[i].vDt = (real)vDt;
176 h_OptionData[i].puByDf = (real)puByDf;
177 h_OptionData[i].pdByDf = (real)pdByDf;
180 checkCudaErrors(cudaMemcpyToSymbol(d_OptionData, h_OptionData, optN * sizeof(__TOptionData)));
181 binomialOptionsKernel<<<optN, CACHE_SIZE>>>();
182 getLastCudaError("binomialOptionsKernel() execution failed.\n");
183 checkCudaErrors(cudaMemcpyFromSymbol(callValue, d_CallValue, optN *sizeof(float)));