Skip to content

Commit 0473aa9

Browse files
committed
aula 19
1 parent 0d9c97a commit 0473aa9

31 files changed

Lines changed: 2225 additions & 1179 deletions

material/aulas/aula19/base.cpp

Whitespace-only changes.

material/aulas/aula19/base.cu

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
#include <chrono>
2+
#include <cmath>
3+
#include <cstdio>
4+
#include <fstream>
5+
#include <iostream>
6+
#include <memory>
7+
#include <random>
8+
#include <string>
9+
#include <cuda_runtime.h>
10+
#include "base.hpp"
11+
12+
//----------------------------------------------------------------------------
13+
// KERNEL find2dMean Calcula a média de cada coluna na GPU
14+
//----------------------------------------------------------------------------
15+
__global__ void find2dMeanKernel(float* d_matrix, float* d_avg, int numLoops, int timeSteps)
16+
{
17+
int col = blockIdx.x * blockDim.x + threadIdx.x;
18+
19+
if (col < timeSteps)
20+
{
21+
float sum = 0.0f;
22+
for (int row = 0; row < numLoops; row++)
23+
{
24+
// Acesso à matriz linearizada [linha * total_colunas + coluna]
25+
sum += d_matrix[row * timeSteps + col];
26+
}
27+
d_avg[col] = sum / numLoops;
28+
}
29+
}
30+
31+
//----------------------------------------------------------------------------
32+
// FUNÇÃO que gerencia os dados da CPU para GPU
33+
//----------------------------------------------------------------------------
34+
float* find2dMeanGPU(float* h_matrix, int numLoops, int timeSteps)
35+
{
36+
size_t matrixSize = numLoops * timeSteps * sizeof(float);
37+
size_t avgSize = timeSteps * sizeof(float);
38+
float *d_matrix, *d_avg;
39+
float* h_avg = new float[timeSteps];
40+
41+
// 1. Alocar memória na GPU
42+
cudaMalloc(&d_matrix, matrixSize);
43+
cudaMalloc(&d_avg, avgSize);
44+
45+
// 2. Copiar dados da CPU para a GPU
46+
cudaMemcpy(d_matrix, h_matrix, matrixSize, cudaMemcpyHostToDevice);
47+
48+
// 4. Executar o kernel
49+
int threadsPerBlock = 256;
50+
int blocksPerGrid = (timeSteps + threadsPerBlock - 1) / threadsPerBlock;
51+
find2dMeanKernel<<<blocksPerGrid, threadsPerBlock>>>(d_matrix, d_avg, numLoops, timeSteps);
52+
53+
// 5. Copiar o resultado da GPU para a CPU
54+
cudaMemcpy(h_avg, d_avg, avgSize, cudaMemcpyDeviceToHost);
55+
56+
// 6. Liberar a memória da GPU
57+
cudaFree(d_matrix);
58+
cudaFree(d_avg);
59+
60+
return h_avg;
61+
}
62+
63+
64+
//----------------------------------------------------------------------------
65+
// Calcula a volatilidade a partir do arquivo data.csv
66+
//----------------------------------------------------------------------------
67+
float calculateVolatility(float spotPrice, int32_t timeSteps)
68+
{
69+
// Abre o arquivo data.csv em modo de leitura, encerra em caso de falha
70+
std::ifstream filePtr;
71+
filePtr.open("nvidia_stock.txt", std::ifstream::in);
72+
73+
if (!filePtr.is_open())
74+
{
75+
std::cerr << "Não foi possível abrir o arquivo! Encerrando..\n";
76+
exit(EXIT_FAILURE);
77+
}
78+
79+
int32_t i = 0;
80+
int32_t maxLen = timeSteps - 1;
81+
std::unique_ptr<float[]> priceArr = std::make_unique<float[]>(maxLen);
82+
std::string line;
83+
84+
while( std::getline(filePtr, line) && (i < maxLen) ){
85+
if(line.empty()) continue;
86+
87+
try {
88+
priceArr[i] = std::stof(line);
89+
i++;
90+
91+
} catch (const std::exception& e){
92+
std::cerr << "Erro ao converter o valor da linha " << i <<"\n";
93+
continue;
94+
}
95+
96+
}
97+
filePtr.close();
98+
99+
float sum = spotPrice;
100+
// Encontra a média dos preços estimados no final de cada minuto
101+
for (i = 0; i < maxLen; i++){
102+
sum += priceArr[i];
103+
}
104+
float meanPrice = sum / (maxLen + 1);
105+
106+
// Calcula a volatilidade do mercado como o desvio padrão
107+
sum = std::pow((spotPrice - meanPrice), 2.0f);
108+
for (i = 0; i < maxLen; i++){
109+
sum += std::pow((priceArr[i] - meanPrice), 2.0f);
110+
}
111+
112+
float stdDev = std::sqrt(sum / maxLen); // Nota: Fórmula do desvio padrão amostral requer divisão pelo tamanho
113+
114+
// Retorna como porcentagem
115+
return stdDev / 100.0f;
116+
}
117+
118+
119+
/** ---------------------------------------------------------------------------
120+
Gera um número aleatório semeado pelo relógio do sistema baseado na
121+
distribuição normal padrão assumindo média 0.0 e desvio padrão 1.0
122+
----------------------------------------------------------------------------*/
123+
float genRand(float mean, float stdDev)
124+
{
125+
const auto seed = std::chrono::system_clock::now().time_since_epoch().count();
126+
std::default_random_engine generator(static_cast<uint32_t>(seed));
127+
std::normal_distribution<float> distribution(mean, stdDev);
128+
return distribution(generator);
129+
}
130+
131+
//----------------------------------------------------------------------------
132+
// Simula o modelo de Black-Scholes
133+
//----------------------------------------------------------------------------
134+
float* runBlackScholesModel(float spotPrice, int32_t timeSteps, float riskRate, float volatility)
135+
{
136+
// Média e desvio padrão
137+
static constexpr float mean = 0.0f, stdDev = 1.0f;
138+
// Intervalo de tempo (Timestep)
139+
float deltaT = 1.0f / timeSteps;
140+
std::unique_ptr<float[]> normRand = std::make_unique<float[]>(timeSteps - 1); // Array de números aleatórios distribuídos normalmente
141+
float* stockPrice = new float[timeSteps]; // Array do preço da ação em diferentes tempos
142+
stockPrice[0] = spotPrice; // O preço da ação em t=0 é o preço à vista (spot price)
143+
144+
// Preenche o array com números aleatórios
145+
for (int32_t i = 0; i < timeSteps - 1; i++)
146+
normRand[i] = genRand(mean, stdDev);
147+
148+
// Aplica a equação de Black-Scholes para calcular o preço da ação no próximo passo de tempo
149+
for (int32_t i = 0; i < timeSteps - 1; i++)
150+
stockPrice[i + 1] = stockPrice[i] * exp(((riskRate - (std::pow(volatility, 2.0f) / 2.0f)) * deltaT) + (volatility * normRand[i] * std::sqrt(deltaT)));
151+
152+
return stockPrice;
153+
}
154+
155+
156+
void displayHelp(char* programName) {
157+
std::cout << "\n========================================================================\n";
158+
std::cout << " SIMULADOR DE MONTE CARLO - MODELO BLACK-SCHOLES (NVIDIA PREDICT)\n";
159+
std::cout << "========================================================================\n\n";
160+
std::cout << "Uso: " << programName << " [opcionais]\n\n";
161+
std::cout << "Sintaxe dos Argumentos:\n";
162+
std::cout << " 1. [inLoops] Iterações internas para redução de variância (Padrão: 100)\n";
163+
std::cout << " 2. [outLoops] Total de simulações de Monte Carlo (Padrão: 10000)\n";
164+
std::cout << " 3. [timeStepsHistory] Janela de dados históricos para cálculo de volatilidade (Padrão: 180)\n";
165+
std::cout << " 4. [timeStepsForecast] Horizonte de projeção da série temporal (Padrão: 180)\n";
166+
std::cout << " 5. [spotPrice] Preço atual do ativo (S_0) no tempo zero (Padrão: 0.50)\n";
167+
std::cout << " 6. [riskRate] Taxa livre de risco anualizada (Risk-free rate) (Padrão: 0.5)\n\n";
168+
169+
std::cout << "Descrição Técnica:\n";
170+
std::cout << " Este software realiza uma simulação estocástica baseada no Movimento \n";
171+
std::cout << " Browniano Geométrico. Ele processa dados históricos de fechamento para \n";
172+
std::cout << " derivar a volatilidade implícita e projeta N caminhos possíveis, \n";
173+
std::cout << " consolidando-os em um resultado estatisticamente convergente (opt.csv).\n\n";
174+
175+
std::cout << "Exemplo de execução avançada:\n";
176+
std::cout << " " << programName << " 500 50000 252 30 145.20 0.05\n";
177+
std::cout << " (Simula 30 dias com 25 milhões de trajetórias totais)\n";
178+
std::cout << "========================================================================\n\n";
179+
}
180+
181+
182+
/* ============================================================================
183+
APLICAÇÃO DO MÉTODO DE MONTE CARLO
184+
----------------------------------
185+
O Método de Monte Carlo utiliza amostragens aleatórias massivas para modelar
186+
sistemas complexos (que não possuem uma solução exata simples) e estimar os
187+
seus resultados através de probabilidade.
188+
189+
Neste código, ele é aplicado da seguinte forma:
190+
1. Aleatoriedade (Caminhos): O modelo gera múltiplos cenários ou "caminhos"
191+
possíveis para o preço da ação ao longo do tempo usando a equação estocástica
192+
de Black-Scholes (movimento browniano geométrico), impulsionada pela
193+
função de números aleatórios 'genRand'.
194+
2. Repetição: Executamos milhares dessas simulações independentes através de
195+
laços de repetição aninhados (controlados por 'inLoops' e 'outLoops').
196+
3. Agregação: Ao final, calculamos a média (find2dMean) de todos esses caminhos
197+
simulados. Pela Lei dos Grandes Números, a média destas simulações converge
198+
para o valor esperado ou o "resultado mais provável" do comportamento da
199+
ação ao longo do tempo em um mercado volátil.
200+
============================================================================ */
201+
202+
//----------------------------------------------------------------------------
203+
// Função Principal
204+
//----------------------------------------------------------------------------
205+
206+
207+
int32_t run(int32_t inLoops, int32_t outLoops, int32_t timeStepsHistory,
208+
int32_t timeStepsForecast, float spotPrice, float riskRate)
209+
{
210+
// Agora usamos memória linear para facilitar a transferência para GPU
211+
float* h_stockFlat = new float[inLoops * timeStepsForecast];
212+
float* h_avgStockFlat = new float[outLoops * timeStepsForecast];
213+
214+
const float volatility = calculateVolatility(spotPrice, timeStepsHistory);
215+
216+
std::cout << "Usando volatilidade de mercado: " << volatility << "\n";
217+
std::cout << "Executando aceleração via GPU (Kernel find2dMean)\n\n";
218+
219+
for (int32_t i = 0; i < outLoops; i++)
220+
{
221+
for (int32_t j = 0; j < inLoops; j++)
222+
{
223+
float* path = runBlackScholesModel(spotPrice, timeStepsForecast, riskRate, volatility);
224+
// Copia o caminho para a matriz linearizada
225+
for(int k=0; k < timeStepsForecast; k++) {
226+
h_stockFlat[j * timeStepsForecast + k] = path[k];
227+
}
228+
delete[] path;
229+
}
230+
231+
// CHAMA A GPU para processar as médias do bloco interno
232+
float* avgResult = find2dMeanGPU(h_stockFlat, inLoops, timeStepsForecast);
233+
234+
// Armazena na matriz de médias global
235+
for(int k=0; k < timeStepsForecast; k++) {
236+
h_avgStockFlat[i * timeStepsForecast + k] = avgResult[k];
237+
}
238+
delete[] avgResult;
239+
}
240+
241+
// Calcula o resultado final (Média das Médias) também na GPU
242+
float* optStock = find2dMeanGPU(h_avgStockFlat, outLoops, timeStepsForecast);
243+
244+
// Grava o resultado
245+
std::ofstream filePtr("opt.csv");
246+
if (filePtr.is_open()) {
247+
for (int32_t i = 0; i < timeStepsForecast; i++)
248+
filePtr << optStock[i] << "\n";
249+
filePtr.close();
250+
}
251+
252+
delete[] h_stockFlat;
253+
delete[] h_avgStockFlat;
254+
delete[] optStock;
255+
256+
return EXIT_SUCCESS;
257+
}
258+
259+
int32_t timed_run(int32_t inLoops, int32_t outLoops, int32_t timeStepsHistory,
260+
int32_t timeStepsForecast, float_t spotPrice, float_t riskRate){
261+
const auto beginTime = std::chrono::steady_clock::now();
262+
263+
if(run(inLoops, outLoops, timeStepsHistory, timeStepsForecast, spotPrice, riskRate)){
264+
return -1;
265+
}
266+
267+
const auto endTime = std::chrono::steady_clock::now();
268+
const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - beginTime).count();
269+
return elapsed;
270+
}
271+
272+
273+
int main(int argc, char** argv)
274+
{
275+
static int inLoops = 100; // Iterações do laço interno
276+
static int outLoops = 100; // Iterações do laço externo
277+
static int timeStepsHistory = 100; // Intervalos de tempo do mercado de ações (dias)
278+
static int timeStepsForecast = 100; // Intervalos de tempo do mercado de ações (dias)
279+
static float spotPrice = 0.50f; // Preço à vista (spot price em t = 0)
280+
static float riskRate = 0.5; // Taxa de juros livre de risco (%)
281+
282+
if ( (argc != 1 ) && ( argc != 7 )){
283+
displayHelp(argv[0]);
284+
return 0;
285+
}
286+
287+
inLoops = std::stoi(argv[1]);
288+
outLoops = std::stoi(argv[2]);
289+
timeStepsHistory = std::stoi(argv[3]);
290+
timeStepsForecast = std::stoi(argv[4]);
291+
spotPrice = std::stof(argv[5]);
292+
riskRate = std::stof(argv[6]);
293+
294+
std::cout << "--- Configurações da Simulação ---" << "\n";
295+
std::cout << "Laços Internos: " << inLoops << "\n";
296+
std::cout << "Laços Externos: " << outLoops << "\n";
297+
std::cout << "Histórico (dias): " << timeStepsHistory << "\n";
298+
std::cout << "Previsão (dias): " << timeStepsForecast << "\n";
299+
std::cout << "Preço Inicial: " << spotPrice << "\n";
300+
std::cout << "Taxa de Risco: " << riskRate << "\n";
301+
std::cout << "----------------------------------" << "\n";
302+
303+
304+
int elapsed = timed_run(inLoops, outLoops, timeStepsHistory, timeStepsForecast, spotPrice, riskRate);
305+
306+
std::cout << "Executado em " << elapsed << " s\n";
307+
308+
309+
return 0;
310+
}

material/aulas/aula19/image-1.png

35.8 KB
Loading

material/aulas/aula19/image-2.png

57.2 KB
Loading

material/aulas/aula19/image-3.png

147 KB
Loading

material/aulas/aula19/image-4.png

94.4 KB
Loading

material/aulas/aula19/image-5.png

135 KB
Loading

material/aulas/aula19/image-6.png

54.7 KB
Loading

material/aulas/aula19/image-7.png

44.6 KB
Loading

material/aulas/aula19/image-8.png

103 KB
Loading

0 commit comments

Comments
 (0)