black_scholes.jl 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. # StarPU --- Runtime system for heterogeneous multicore architectures.
  2. #
  3. # Copyright (C) 2020 Université de Bordeaux, CNRS (LaBRI UMR 5800), Inria
  4. #
  5. # StarPU is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU Lesser General Public License as published by
  7. # the Free Software Foundation; either version 2.1 of the License, or (at
  8. # your option) any later version.
  9. #
  10. # StarPU is distributed in the hope that it will be useful, but
  11. # WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. #
  14. # See the GNU Lesser General Public License in COPYING.LGPL for more details.
  15. #
  16. import Libdl
  17. using StarPU
  18. @target STARPU_CPU+STARPU_CUDA
  19. @codelet function black_scholes(data ::Matrix{Float64}, res ::Matrix{Float64}) :: Float32
  20. widthn ::Int64 = width(data)
  21. # data[1,...] -> S
  22. # data[2,...] -> K
  23. # data[3,...] -> r
  24. # data[4,...] -> T
  25. # data[4,...] -> sig
  26. p ::Float64 = 0.2316419
  27. b1 ::Float64 = 0.31938153
  28. b2 ::Float64 = -0.356563782
  29. b3 ::Float64 = 1.781477937
  30. b4 ::Float64 = -1.821255978
  31. b5 ::Float64 = 1.330274428
  32. @parallel for i = 1:widthn
  33. d1 ::Float64 = (log(data[1,i] / data[2,i]) + (data[3,i] + pow(data[5,i], 2.0) * 0.5) * data[4,i]) / (data[5,i] * sqrt(data[4,i]))
  34. d2 ::Float64 = (log(data[1,i] / data[2,i]) + (data[3,i] - pow(data[5,i], 2.0) * 0.5) * data[4,i]) / (data[5,i] * sqrt(data[4,i]))
  35. f ::Float64 = 0
  36. ff ::Float64 = 0
  37. s1 ::Float64 = 0
  38. s2 ::Float64 = 0
  39. s3 ::Float64 = 0
  40. s4 ::Float64 = 0
  41. s5 ::Float64 = 0
  42. sz ::Float64 = 0
  43. ######## Compute normcdf of d1
  44. normd1p ::Float64 = 0
  45. normd1n ::Float64 = 0
  46. boold1 ::Int64 = (d1 >= 0) + (d1 <= 0)
  47. if (boold1 >= 2)
  48. normd1p = 0.5
  49. normd1n = 0.5
  50. else
  51. tmp1 ::Float64 = abs(d1)
  52. f = 1 / sqrt(2 * M_PI)
  53. ff = exp(-pow(tmp1, 2.0) / 2) * f
  54. s1 = b1 / (1 + p * tmp1)
  55. s2 = b2 / pow((1 + p * tmp1), 2.0)
  56. s3 = b3 / pow((1 + p * tmp1), 3.0)
  57. s4 = b4 / pow((1 + p * tmp1), 4.0)
  58. s5 = b5 / pow((1 + p * tmp1), 5.0)
  59. sz = ff * (s1 + s2 + s3 + s4 + s5)
  60. if (d1 > 0)
  61. normd1p = 1 - sz # normcdf(d1)
  62. normd1n = sz # normcdf(-d1)
  63. else
  64. normd1p = sz
  65. normd1n = 1 - sz
  66. end
  67. end
  68. ########
  69. ######## Compute normcdf of d2
  70. normd2p ::Float64 = 0
  71. normd2n ::Float64 = 0
  72. boold2 ::Int64 = (d2 >= 0) + (d2 <= 0)
  73. if (boold2 >= 2)
  74. normd2p = 0.5
  75. normd2n = 0.5
  76. else
  77. tmp2 ::Float64 = abs(d2)
  78. f = 1 / sqrt(2 * M_PI)
  79. ff = exp(-pow(tmp2, 2.0) / 2) * f
  80. s1 = b1 / (1 + p * tmp2)
  81. s2 = b2 / pow((1 + p * tmp2), 2.0)
  82. s3 = b3 / pow((1 + p * tmp2), 3.0)
  83. s4 = b4 / pow((1 + p * tmp2), 4.0)
  84. s5 = b5 / pow((1 + p * tmp2), 5.0)
  85. sz = ff * (s1 + s2 + s3 + s4 + s5)
  86. if (d2 > 0)
  87. normd2p = 1 - sz # normcdf(d2)
  88. normd2n = sz # normcdf(-d2)
  89. else
  90. normd2p = sz
  91. normd2n = 1 - sz
  92. end
  93. end
  94. # normd1p = (1 + erf(d1/sqrt(2.0)))/2.0
  95. # normd1n = (1 + erf(-d1/sqrt(2.0)))/2.0
  96. # normd2p = (1 + erf(d2/sqrt(2.0)))/2.0
  97. # normd2n = (1 + erf(-d2/sqrt(2.0)))/2.0
  98. res[1,i] = data[1,i] * (normd1p) - data[2,i]*exp(-data[3,i]*data[4,i]) * (normd2p) # S * N(d1) - r*exp(-r*T) * norm(d2)
  99. res[2,i] = -data[1,i] * (normd1n) + data[2,i]*exp(-data[3,i]*data[4,i]) * (normd2n) # -S * N(-d1) + r*exp(-r*T) * norm(-d2)
  100. end
  101. return 0
  102. end
  103. starpu_init()
  104. function black_scholes_starpu(data ::Matrix{Float64}, res ::Matrix{Float64}, nslices ::Int64)
  105. vert = StarpuDataFilter(STARPU_MATRIX_FILTER_VERTICAL_BLOCK, nslices)
  106. @starpu_block let
  107. dat_handle, res_handle = starpu_data_register(data, res)
  108. starpu_data_partition(dat_handle, vert)
  109. starpu_data_partition(res_handle, vert)
  110. #Compute the price of call and put option in the res matrix
  111. @starpu_sync_tasks for task in (1:nslices)
  112. @starpu_async_cl black_scholes(dat_handle[task], res_handle[task]) [STARPU_RW, STARPU_RW]
  113. end
  114. end
  115. return 0
  116. end
  117. function init_data(data, data_nbr);
  118. for i in 1:data_nbr
  119. data[1,i] = rand(Float64) * 100
  120. data[2,i] = rand(Float64) * 100
  121. data[3,i] = rand(Float64)
  122. data[4,i] = rand(Float64) * 10
  123. data[5,i] = rand(Float64) * 10
  124. end
  125. return data
  126. end
  127. function median_times(data_nbr, nslices, nbr_tests)
  128. data ::Matrix{Float64} = zeros(5, data_nbr)
  129. # data[1,1] = 100.0
  130. # data[2,1] = 100.0
  131. # data[3,1] = 0.05
  132. # data[4,1] = 1.0
  133. # data[5,1] = 0.2
  134. res ::Matrix{Float64} = zeros(2, data_nbr)
  135. exec_times ::Vector{Float64} = [0. for i in 1:nbr_tests]
  136. for i = 1:nbr_tests
  137. init_data(data, data_nbr)
  138. tic()
  139. black_scholes_starpu(data, res, nslices);
  140. t = toq()
  141. exec_times[i] = t
  142. end
  143. sort!(exec_times)
  144. # println(data)
  145. # println(res)
  146. return exec_times[1 + div(nbr_tests - 1, 2)]
  147. end
  148. function display_times(start_nbr, step_nbr, stop_nbr, nslices, nbr_tests)
  149. i = 1
  150. open("black_scholes_times.dat", "w") do f
  151. for data_nbr in (start_nbr : step_nbr : stop_nbr)
  152. t = median_times(data_nbr, nslices, nbr_tests)
  153. println("Number of data:\n$data_nbr\nTimes:\njl: $t\nC: $(mtc[i])\nGen: $(mtcgen[i])")
  154. write(f, "$data_nbr $(t)\n")
  155. i = i + 1
  156. end
  157. end
  158. end