// File: /workspace/github_cpp_makefile_star2_O2/ArashPartow[P]exprtk/exprtk_simple_example_15.cpp
// Function: void black_scholes_merton_model<double>()
void black_scholes_merton_model()
{
   typedef exprtk::symbol_table<T> symbol_table_t;
   typedef exprtk::expression<T>   expression_t;
   typedef exprtk::parser<T>       parser_t;

   const std::string bsm_model_program =
      " var d1 := (log(s / k) + (r + v^2 / 2) * t) / (v * sqrt(t)); "
      " var d2 := d1 - v * sqrt(t);                                 "
      "                                                             "
      " if (callput_flag == 'call')                                 "
      "    s * ncdf(d1) - k * e^(-r * t) * ncdf(d2);                "
      " else if (callput_flag == 'put')                             "
      "    k * e^(-r * t) * ncdf(-d2) - s * ncdf(-d1);              "
      "                                                             ";

   T s = T(60.00); // Spot / Stock / Underlying / Base price
   T k = T(65.00); // Strike price
   T v = T( 0.30); // Volatility
   T t = T( 0.25); // Years to maturity
   T r = T( 0.08); // Risk free rate

   std::string callput_flag;

   static const T e = exprtk::details::numeric::constant::e;

   symbol_table_t symbol_table;
   symbol_table.add_variable("s",s);
   symbol_table.add_variable("k",k);
   symbol_table.add_variable("t",t);
   symbol_table.add_variable("r",r);
   symbol_table.add_variable("v",v);
   symbol_table.add_constant("e",e);
   symbol_table.add_stringvar("callput_flag",callput_flag);

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   parser_t parser;
   parser.compile(bsm_model_program,expression);

   callput_flag = "call";

   const T bsm_call_option_price = expression.value();

   callput_flag = "put";

   const T bsm_put_option_price = expression.value();

   printf("BSM(call, %5.3f, %5.3f, %5.3f, %5.3f, %5.3f) = %10.6f\n",
          s, k, t, r, v,
          bsm_call_option_price);

   printf("BSM(put , %5.3f, %5.3f, %5.3f, %5.3f, %5.3f) = %10.6f\n",
          s, k, t, r, v,
          bsm_put_option_price);

   const T put_call_parity_diff =
      (bsm_call_option_price - bsm_put_option_price) -
      (s - k * std::exp(-r * t));

   printf("Put-Call parity difference: %20.17f\n", put_call_parity_diff);
}

// Assembly:
pushq %rbx
subq $0xb20, %rsp            # imm = 0xB20
leaq 0x12adff(%rip), %rsi    # 0x23b101
leaq 0x88(%rsp), %rdi
leaq 0x1f8(%rsp), %rdx
callq 0x1102b8
movabsq $0x404e000000000000, %rax # imm = 0x404E000000000000
movq %rax, 0x30(%rsp)
movabsq $0x4050400000000000, %rax # imm = 0x4050400000000000
movq %rax, 0x28(%rsp)
movabsq $0x3fd3333333333333, %rax # imm = 0x3FD3333333333333
movq %rax, 0x38(%rsp)
movabsq $0x3fd0000000000000, %rax # imm = 0x3FD0000000000000
movq %rax, 0x20(%rsp)
movabsq $0x3fb47ae147ae147b, %rax # imm = 0x3FB47AE147AE147B
movq %rax, 0x18(%rsp)
leaq 0x78(%rsp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
movq %rsp, %rdi
pushq $0x1
popq %rsi
callq 0x110830
leaq 0x12ac2c(%rip), %rsi    # 0x23afb1
leaq 0x1f8(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x1f8(%rsp), %rsi
leaq 0x30(%rsp), %rdx
xorl %ecx, %ecx
callq 0x110854
leaq 0x1f8(%rsp), %rdi
callq 0x10e5b8
leaq 0x12ab7f(%rip), %rsi    # 0x23af44
leaq 0x1f8(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x1f8(%rsp), %rsi
leaq 0x28(%rsp), %rdx
xorl %ecx, %ecx
callq 0x110854
leaq 0x1f8(%rsp), %rdi
callq 0x10e5b8
leaq 0x12b62c(%rip), %rsi    # 0x23ba31
leaq 0x1f8(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x1f8(%rsp), %rsi
leaq 0x20(%rsp), %rdx
xorl %ecx, %ecx
callq 0x110854
leaq 0x1f8(%rsp), %rdi
callq 0x10e5b8
leaq 0x12ab57(%rip), %rsi    # 0x23af9c
leaq 0x1f8(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x1f8(%rsp), %rsi
leaq 0x18(%rsp), %rdx
xorl %ecx, %ecx
callq 0x110854
leaq 0x1f8(%rsp), %rdi
callq 0x10e5b8
leaq 0x12ae65(%rip), %rsi    # 0x23b2ea
leaq 0x1f8(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x1f8(%rsp), %rsi
leaq 0x38(%rsp), %rdx
xorl %ecx, %ecx
callq 0x110854
leaq 0x1f8(%rsp), %rdi
callq 0x10e5b8
leaq 0x12bc5e(%rip), %rsi    # 0x23c123
leaq 0x1f8(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
callq 0x1102b8
leaq 0x12f9af(%rip), %rdx    # 0x23fe90
movq %rsp, %rdi
leaq 0x1f8(%rsp), %rsi
callq 0x1108c0
leaq 0x1f8(%rsp), %rdi
callq 0x10e5b8
leaq 0x12ade7(%rip), %rsi    # 0x23b2ec
leaq 0x1f8(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
callq 0x1102b8
movq %rsp, %rdi
leaq 0x1f8(%rsp), %rsi
leaq 0x68(%rsp), %rdx
xorl %ecx, %ecx
callq 0x11093c
leaq 0x1f8(%rsp), %rdi
callq 0x10e5b8
leaq 0x48(%rsp), %rdi
callq 0x1109ae
leaq 0x48(%rsp), %rdi
movq %rsp, %rsi
callq 0x110a0e
leaq 0xa8(%rsp), %rdi
pushq $0x7f
popq %rsi
callq 0x110a6a
leaq 0x1f8(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0x110b7a
leaq 0xa8(%rsp), %rdi
callq 0x111192
leaq 0x1f8(%rsp), %rdi
leaq 0x88(%rsp), %rsi
leaq 0x48(%rsp), %rdx
callq 0x1111da
leaq 0x12e6ec(%rip), %rsi    # 0x23ec94
leaq 0x68(%rsp), %rdi
callq 0x10e570
movq 0x48(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movsd %xmm0, 0x10(%rsp)
leaq 0x12ad2b(%rip), %rsi    # 0x23b2f9
leaq 0x68(%rsp), %rdi
callq 0x10e570
movq 0x48(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movsd %xmm0, 0x8(%rsp)
movsd 0x30(%rsp), %xmm0
movsd 0x28(%rsp), %xmm1
movsd 0x20(%rsp), %xmm2
movsd 0x18(%rsp), %xmm3
movsd 0x38(%rsp), %xmm4
leaq 0x12aceb(%rip), %rdi    # 0x23b2fd
movsd 0x10(%rsp), %xmm5
movb $0x6, %al
callq 0x10e060
movsd 0x30(%rsp), %xmm0
movsd 0x28(%rsp), %xmm1
movsd 0x20(%rsp), %xmm2
movsd 0x18(%rsp), %xmm3
movsd 0x38(%rsp), %xmm4
leaq 0x12acf0(%rip), %rdi    # 0x23b334
movsd 0x8(%rsp), %xmm5
movb $0x6, %al
callq 0x10e060
movsd 0x10(%rsp), %xmm0
subsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0x30(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
movsd 0x28(%rsp), %xmm0
movsd %xmm0, 0x40(%rsp)
movsd 0x18(%rsp), %xmm0
xorpd 0x125987(%rip), %xmm0   # 0x236010
mulsd 0x20(%rsp), %xmm0
callq 0x10e0d0
mulsd 0x40(%rsp), %xmm0
movsd 0x8(%rsp), %xmm1
subsd %xmm0, %xmm1
movsd 0x10(%rsp), %xmm0
subsd %xmm1, %xmm0
leaq 0x12acb6(%rip), %rdi    # 0x23b36b
movb $0x1, %al
callq 0x10e060
leaq 0x1f8(%rsp), %rdi
callq 0x11165c
leaq 0x48(%rsp), %rdi
callq 0x111796
movq %rsp, %rdi
callq 0x1117ac
leaq 0x68(%rsp), %rdi
callq 0x10e5b8
leaq 0x88(%rsp), %rdi
callq 0x10e5b8
addq $0xb20, %rsp            # imm = 0xB20
popq %rbx
retq
jmp 0x11074e
movq %rax, %rbx
leaq 0xa8(%rsp), %rdi
callq 0x111192
jmp 0x11075e
jmp 0x110711
movq %rax, %rbx
jmp 0x11075e
jmp 0x110742
jmp 0x110730
jmp 0x110742
jmp 0x110730
jmp 0x110742
jmp 0x110730
jmp 0x110742
jmp 0x110730
jmp 0x110742
jmp 0x110730
jmp 0x110742
jmp 0x110730
jmp 0x110742
movq %rax, %rbx
leaq 0x1f8(%rsp), %rdi
callq 0x10e5b8
jmp 0x110768
movq %rax, %rbx
jmp 0x110768
movq %rax, %rbx
jmp 0x110770
jmp 0x11074e
movq %rax, %rbx
leaq 0x1f8(%rsp), %rdi
callq 0x11165c
leaq 0x48(%rsp), %rdi
callq 0x111796
movq %rsp, %rdi
callq 0x1117ac
leaq 0x68(%rsp), %rdi
callq 0x10e5b8
leaq 0x88(%rsp), %rdi
callq 0x10e5b8
movq %rbx, %rdi
callq 0x10e310