最佳答案
为了完成这项作业,我已经绞尽脑汁一个星期了,我希望这里有人能指引我走上正确的道路。让我从教练的指导开始:
你的作业和我们第一个实验作业正好相反,第一个实验作业是优化一个质数程序。你在这项作业中的目的是使程序变得悲观,即使它运行得慢一些。这两个程序都是cpu密集型程序。它们需要几秒钟才能在我们的实验室电脑上运行。你不能改变算法。
要对程序进行反优化,请使用您对Intel i7管道如何运行的了解。想象一下重新排序指令路径以引入WAR、RAW和其他危险的方法。考虑一些方法来最小化缓存的有效性。极度无能。
作业要求在磨石或蒙特卡洛程序中进行选择。缓存效率注释大多只适用于Whetstone,但我选择了Monte-Carlo模拟程序:
// Un-modified baseline for pessimization, as given in the assignment
#include <algorithm> // Needed for the "max" function
#include <cmath>
#include <iostream>
// A simple implementation of the Box-Muller algorithm, used to generate
// gaussian random numbers - necessary for the Monte Carlo method below
// Note that C++11 actually provides std::normal_distribution<> in
// the <random> library, which can be used instead of this function
double gaussian_box_muller() {
double x = 0.0;
double y = 0.0;
double euclid_sq = 0.0;
// Continue generating two uniform random variables
// until the square of their "euclidean distance"
// is less than unity
do {
x = 2.0 * rand() / static_cast<double>(RAND_MAX)-1;
y = 2.0 * rand() / static_cast<double>(RAND_MAX)-1;
euclid_sq = x*x + y*y;
} while (euclid_sq >= 1.0);
return x*sqrt(-2*log(euclid_sq)/euclid_sq);
}
// Pricing a European vanilla call option with a Monte Carlo method
double monte_carlo_call_price(const int& num_sims, const double& S, const double& K, const double& r, const double& v, const double& T) {
double S_adjust = S * exp(T*(r-0.5*v*v));
double S_cur = 0.0;
double payoff_sum = 0.0;
for (int i=0; i<num_sims; i++) {
double gauss_bm = gaussian_box_muller();
S_cur = S_adjust * exp(sqrt(v*v*T)*gauss_bm);
payoff_sum += std::max(S_cur - K, 0.0);
}
return (payoff_sum / static_cast<double>(num_sims)) * exp(-r*T);
}
// Pricing a European vanilla put option with a Monte Carlo method
double monte_carlo_put_price(const int& num_sims, const double& S, const double& K, const double& r, const double& v, const double& T) {
double S_adjust = S * exp(T*(r-0.5*v*v));
double S_cur = 0.0;
double payoff_sum = 0.0;
for (int i=0; i<num_sims; i++) {
double gauss_bm = gaussian_box_muller();
S_cur = S_adjust * exp(sqrt(v*v*T)*gauss_bm);
payoff_sum += std::max(K - S_cur, 0.0);
}
return (payoff_sum / static_cast<double>(num_sims)) * exp(-r*T);
}
int main(int argc, char **argv) {
// First we create the parameter list
int num_sims = 10000000; // Number of simulated asset paths
double S = 100.0; // Option price
double K = 100.0; // Strike price
double r = 0.05; // Risk-free rate (5%)
double v = 0.2; // Volatility of the underlying (20%)
double T = 1.0; // One year until expiry
// Then we calculate the call/put values via Monte Carlo
double call = monte_carlo_call_price(num_sims, S, K, r, v, T);
double put = monte_carlo_put_price(num_sims, S, K, r, v, T);
// Finally we output the parameters and prices
std::cout << "Number of Paths: " << num_sims << std::endl;
std::cout << "Underlying: " << S << std::endl;
std::cout << "Strike: " << K << std::endl;
std::cout << "Risk-Free Rate: " << r << std::endl;
std::cout << "Volatility: " << v << std::endl;
std::cout << "Maturity: " << T << std::endl;
std::cout << "Call Price: " << call << std::endl;
std::cout << "Put Price: " << put << std::endl;
return 0;
}
我所做的更改似乎增加了一秒钟的代码运行时间,但我不完全确定我可以在不添加代码的情况下更改什么来暂停管道。一个指向正确方向的点将是非常棒的,我感谢任何回复。
重点是:
CPUID
指令和如何确定缓存大小,以及intrinsic和CLFLUSH
指令。Cowmoogun对元线程的注释表明不清楚编译器优化可能是其中的一部分,并假设-O0
,运行时增加17%是合理的。
听起来作业的目标是让学生重新排列现有的作业,以减少指令级的并行性或类似的事情,但这并不是一件坏事,人们钻研得更深入,学得更多。
请记住,这是一个计算机体系结构问题,而不是一个关于如何使c++变慢的问题。