mesytec-mnode/external/taskflow-3.8.0/benchmarks/black_scholes/common.hpp
2025-01-04 01:25:05 +01:00

269 lines
6.6 KiB
C++

#pragma once
#include <stdlib.h>
#include <math.h>
#include <string>
#include <cassert>
#include <iostream>
#include <chrono>
#include <fstream>
#include <memory>
#include <random>
//Precision to use for calculations
typedef struct OptionData_ {
float s; // spot price
float strike; // strike price
float r; // risk-free interest rate
float divq; // dividend rate
float v; // volatility
float t; // time to maturity or option expiration in years
// (1yr = 1.0, 6mos = 0.5, 3mos = 0.25, ..., etc)
char OptionType; // Option type. "P"=PUT, "C"=CALL
float divs; // dividend vals (not used in this test)
float DGrefval; // DerivaGem Reference Value
} OptionData;
extern OptionData *optdata;
extern float *prices;
extern int numOptions;
extern int NUM_RUNS;
extern int* otype;
extern float* sptprice;
extern float* strike;
extern float* rate;
extern float* volatility;
extern float* otime;
extern int numError;
extern float* BUFFER;
extern int* BUFFER2;
////////////////////////////////////////////////////////////////////////////////
// Cumulative Normal Distribution Function
// See Hull, Section 11.8, P.243-244
////////////////////////////////////////////////////////////////////////////////
#define inv_sqrt_2xPI 0.39894228040143270286
inline float CNDF( float InputX ) {
int sign;
float OutputX;
float xInput;
float xNPrimeofX;
float expValues;
float xK2;
float xK2_2, xK2_3;
float xK2_4, xK2_5;
float xLocal, xLocal_1;
float xLocal_2, xLocal_3;
// Check for negative value of InputX
if (InputX < 0.0) {
InputX = -InputX;
sign = 1;
}
else {
sign = 0;
}
xInput = InputX;
// Compute NPrimeX term common to both four & six decimal accuracy calcs
expValues = std::exp(-0.5f * InputX * InputX);
xNPrimeofX = expValues;
xNPrimeofX = xNPrimeofX * inv_sqrt_2xPI;
xK2 = 0.2316419 * xInput;
xK2 = 1.0 + xK2;
xK2 = 1.0 / xK2;
xK2_2 = xK2 * xK2;
xK2_3 = xK2_2 * xK2;
xK2_4 = xK2_3 * xK2;
xK2_5 = xK2_4 * xK2;
xLocal_1 = xK2 * 0.319381530;
xLocal_2 = xK2_2 * (-0.356563782);
xLocal_3 = xK2_3 * 1.781477937;
xLocal_2 = xLocal_2 + xLocal_3;
xLocal_3 = xK2_4 * (-1.821255978);
xLocal_2 = xLocal_2 + xLocal_3;
xLocal_3 = xK2_5 * 1.330274429;
xLocal_2 = xLocal_2 + xLocal_3;
xLocal_1 = xLocal_2 + xLocal_1;
xLocal = xLocal_1 * xNPrimeofX;
xLocal = 1.0 - xLocal;
OutputX = xLocal;
if (sign) {
OutputX = 1.0 - OutputX;
}
return OutputX;
}
inline float BlkSchlsEqEuroNoDiv(
float sptprice, float strike, float rate,
float volatility, float time, int otype, float) {
float OptionPrice;
// local private working variables for the calculation
//float xStockPrice; // These two variables are not used
//float xStrikePrice;
float xRiskFreeRate;
float xVolatility;
float xTime;
float xSqrtTime;
float logValues;
float xLogTerm;
float xD1;
float xD2;
float xPowerTerm;
float xDen;
float d1;
float d2;
float FutureValueX;
float NofXd1;
float NofXd2;
float NegNofXd1;
float NegNofXd2;
//xStockPrice = sptprice;
//xStrikePrice = strike;
xRiskFreeRate = rate;
xVolatility = volatility;
xTime = time;
xSqrtTime = std::sqrt(xTime);
logValues = std::log(sptprice/strike);
xLogTerm = logValues;
xPowerTerm = xVolatility * xVolatility;
xPowerTerm = xPowerTerm * 0.5;
xD1 = xRiskFreeRate + xPowerTerm;
xD1 = xD1 * xTime;
xD1 = xD1 + xLogTerm;
xDen = xVolatility * xSqrtTime;
xD1 = xD1 / xDen;
xD2 = xD1 - xDen;
d1 = xD1;
d2 = xD2;
NofXd1 = CNDF( d1 );
NofXd2 = CNDF( d2 );
FutureValueX = strike * ( std::exp( -(rate)*(time) ) );
if (otype == 0) {
OptionPrice = (sptprice * NofXd1) - (FutureValueX * NofXd2);
}
else {
NegNofXd1 = (1.0 - NofXd1);
NegNofXd2 = (1.0 - NofXd2);
OptionPrice = (FutureValueX * NegNofXd2) - (sptprice * NegNofXd1);
}
return OptionPrice;
}
inline void check_error(unsigned i, float price) {
float priceDelta = optdata[i].DGrefval - price;
if(std::fabs(priceDelta) >= 1e-4 ){
printf("Error on %d. Computed=%.5f, Ref=%.5f, Delta=%.5f\n",
i, price, optdata[i].DGrefval, priceDelta);
numError ++;
}
}
// Sequential version
inline void bs_seq(float *seq_prices) {
int i, j;
float price;
for (j=0; j<NUM_RUNS; j++) {
for (i=0; i<numOptions; i++) {
/* Calling main function to calculate option value based on
* Black & Scholes's equation.
*/
price = BlkSchlsEqEuroNoDiv( sptprice[i], strike[i],
rate[i], volatility[i], otime[i],
otype[i], 0);
seq_prices[i] = price;
#ifdef ERR_CHK
check_error(i, seq_prices[i]);
#endif
}
}
}
inline void destroy_options() {
free(optdata);
free(prices);
free(BUFFER);
free(BUFFER2);
}
// Read input option data from file
inline void generate_options(size_t num_options) {
numOptions = num_options == 0 ? 1 : num_options;
NUM_RUNS = numOptions;
// Allocate spaces for the option data
optdata = static_cast<OptionData*>(malloc(numOptions*sizeof(OptionData)));
prices = static_cast<float*>(malloc(numOptions*sizeof(float)));
for(int i=0; i<numOptions; ++i) {
optdata[i].s = ::rand() % 200;
optdata[i].strike = ::rand() % 200;
optdata[i].r = 0.1f;
optdata[i].divq = 0.0f;
optdata[i].v = ::rand() % 100 / 100.0f;
optdata[i].t = ::rand() % 100 / 100.0f;
optdata[i].OptionType = ::rand() % 2 ? 'P' : 'C';
optdata[i].divs = 0.0f;
optdata[i].DGrefval = ::rand() % 20;
}
const int PAD {256};
const int LINESIZE {64};
BUFFER = static_cast<float *>(malloc(5 * numOptions * sizeof(float) + PAD));
sptprice = reinterpret_cast<float *>(((unsigned long long)BUFFER + PAD) & ~(LINESIZE - 1));
strike = sptprice + numOptions;
rate = strike + numOptions;
volatility = rate + numOptions;
otime = volatility + numOptions;
BUFFER2 = static_cast<int *>(malloc(numOptions * sizeof(float) + PAD));
//otype = (int *) (((unsigned long long)BUFFER2 + PAD) & ~(LINESIZE - 1));
otype = reinterpret_cast<int *>(((unsigned long long)BUFFER2 + PAD) & ~(LINESIZE - 1));
for(auto i=0; i<numOptions; i++) {
otype[i] = (optdata[i].OptionType == 'P') ? 1 : 0;
sptprice[i] = optdata[i].s;
strike[i] = optdata[i].strike;
rate[i] = optdata[i].r;
volatility[i] = optdata[i].v;
otime[i] = optdata[i].t;
}
}
std::chrono::microseconds measure_time_taskflow(unsigned);
std::chrono::microseconds measure_time_tbb(unsigned);
std::chrono::microseconds measure_time_omp(unsigned);