// File: 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:
subq $0xcb8, %rsp            # imm = 0xCB8
leaq 0xc97(%rsp), %rdi
movq %rdi, 0x60(%rsp)
callq 0x111640
movq 0x60(%rsp), %rdx
leaq 0x330d2c(%rip), %rsi    # 0x449551
leaq 0xc98(%rsp), %rdi
callq 0x118740
jmp 0x118834
leaq 0xc97(%rsp), %rdi
callq 0x111760
movabsq $0x404e000000000000, %rax # imm = 0x404E000000000000
movq %rax, 0xc78(%rsp)
movabsq $0x4050400000000000, %rax # imm = 0x4050400000000000
movq %rax, 0xc70(%rsp)
movabsq $0x3fd3333333333333, %rax # imm = 0x3FD3333333333333
movq %rax, 0xc68(%rsp)
movabsq $0x3fd0000000000000, %rax # imm = 0x3FD0000000000000
movq %rax, 0xc60(%rsp)
movabsq $0x3fb47ae147ae147b, %rax # imm = 0x3FB47AE147AE147B
movq %rax, 0xc58(%rsp)
leaq 0xc38(%rsp), %rdi
callq 0x111260
leaq 0xc30(%rsp), %rdi
movl $0x1, %esi
callq 0x119370
jmp 0x1188bc
leaq 0xc0f(%rsp), %rdi
movq %rdi, 0x58(%rsp)
callq 0x111640
movq 0x58(%rsp), %rdx
leaq 0x330b27(%rip), %rsi    # 0x449401
leaq 0xc10(%rsp), %rdi
callq 0x118740
jmp 0x1188e9
leaq 0xc30(%rsp), %rdi
leaq 0xc10(%rsp), %rsi
leaq 0xc78(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1193b0
jmp 0x11890a
leaq 0xc10(%rsp), %rdi
callq 0x111778
leaq 0xc0f(%rsp), %rdi
callq 0x111760
leaq 0xbe7(%rsp), %rdi
movq %rdi, 0x50(%rsp)
callq 0x111640
movq 0x50(%rsp), %rdx
leaq 0x330a52(%rip), %rsi    # 0x449394
leaq 0xbe8(%rsp), %rdi
callq 0x118740
jmp 0x118951
leaq 0xc30(%rsp), %rdi
leaq 0xbe8(%rsp), %rsi
leaq 0xc70(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1193b0
jmp 0x118972
leaq 0xbe8(%rsp), %rdi
callq 0x111778
leaq 0xbe7(%rsp), %rdi
callq 0x111760
leaq 0xbbf(%rsp), %rdi
movq %rdi, 0x48(%rsp)
callq 0x111640
movq 0x48(%rsp), %rdx
leaq 0x3314c5(%rip), %rsi    # 0x449e6f
leaq 0xbc0(%rsp), %rdi
callq 0x118740
jmp 0x1189b9
leaq 0xc30(%rsp), %rdi
leaq 0xbc0(%rsp), %rsi
leaq 0xc60(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1193b0
jmp 0x1189da
leaq 0xbc0(%rsp), %rdi
callq 0x111778
leaq 0xbbf(%rsp), %rdi
callq 0x111760
leaq 0xb97(%rsp), %rdi
movq %rdi, 0x40(%rsp)
callq 0x111640
movq 0x40(%rsp), %rdx
leaq 0x3309da(%rip), %rsi    # 0x4493ec
leaq 0xb98(%rsp), %rdi
callq 0x118740
jmp 0x118a21
leaq 0xc30(%rsp), %rdi
leaq 0xb98(%rsp), %rsi
leaq 0xc58(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1193b0
jmp 0x118a42
leaq 0xb98(%rsp), %rdi
callq 0x111778
leaq 0xb97(%rsp), %rdi
callq 0x111760
leaq 0xb6f(%rsp), %rdi
movq %rdi, 0x38(%rsp)
callq 0x111640
movq 0x38(%rsp), %rdx
leaq 0x330cc0(%rip), %rsi    # 0x44973a
leaq 0xb70(%rsp), %rdi
callq 0x118740
jmp 0x118a89
leaq 0xc30(%rsp), %rdi
leaq 0xb70(%rsp), %rsi
leaq 0xc68(%rsp), %rdx
xorl %ecx, %ecx
callq 0x1193b0
jmp 0x118aaa
leaq 0xb70(%rsp), %rdi
callq 0x111778
leaq 0xb6f(%rsp), %rdi
callq 0x111760
leaq 0xb47(%rsp), %rdi
movq %rdi, 0x30(%rsp)
callq 0x111640
movq 0x30(%rsp), %rdx
leaq 0x331a7f(%rip), %rsi    # 0x44a561
leaq 0xb48(%rsp), %rdi
callq 0x118740
jmp 0x118af1
leaq 0x335800(%rip), %rdx    # 0x44e2f8
leaq 0xc30(%rsp), %rdi
leaq 0xb48(%rsp), %rsi
callq 0x119460
jmp 0x118b0f
leaq 0xb48(%rsp), %rdi
callq 0x111778
leaq 0xb47(%rsp), %rdi
callq 0x111760
leaq 0xb1f(%rsp), %rdi
movq %rdi, 0x28(%rsp)
callq 0x111640
movq 0x28(%rsp), %rdx
leaq 0x330bf5(%rip), %rsi    # 0x44973c
leaq 0xb20(%rsp), %rdi
callq 0x118740
jmp 0x118b56
leaq 0xc30(%rsp), %rdi
leaq 0xb20(%rsp), %rsi
leaq 0xc38(%rsp), %rdx
xorl %ecx, %ecx
callq 0x119540
jmp 0x118b77
leaq 0xb20(%rsp), %rdi
callq 0x111778
leaq 0xb1f(%rsp), %rdi
callq 0x111760
leaq 0xaf8(%rsp), %rdi
callq 0x119600
jmp 0x118ba0
leaq 0xaf8(%rsp), %rdi
leaq 0xc30(%rsp), %rsi
callq 0x1196b0
jmp 0x118bb7
leaq 0x80(%rsp), %rdi
movl $0x7f, %esi
callq 0x119760
jmp 0x118bcb
leaq 0x1d0(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0x119890
jmp 0x118be2
leaq 0x80(%rsp), %rdi
callq 0x11a0c0
leaq 0x1d0(%rsp), %rdi
leaq 0xc98(%rsp), %rsi
leaq 0xaf8(%rsp), %rdx
callq 0x11a130
jmp 0x118c0e
leaq 0x3344e4(%rip), %rsi    # 0x44d0f9
leaq 0xc38(%rsp), %rdi
callq 0x1112e0
jmp 0x118c24
leaq 0xaf8(%rsp), %rdi
callq 0x11a9c0
movsd %xmm0, 0x20(%rsp)
jmp 0x118c39
movsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x78(%rsp)
leaq 0x330afd(%rip), %rsi    # 0x449749
leaq 0xc38(%rsp), %rdi
callq 0x1112e0
jmp 0x118c5b
leaq 0xaf8(%rsp), %rdi
callq 0x11a9c0
movsd %xmm0, 0x18(%rsp)
jmp 0x118c70
movsd 0x18(%rsp), %xmm0
movsd %xmm0, 0x70(%rsp)
movsd 0xc78(%rsp), %xmm0
movsd 0xc70(%rsp), %xmm1
movsd 0xc60(%rsp), %xmm2
movsd 0xc58(%rsp), %xmm3
movsd 0xc68(%rsp), %xmm4
movsd 0x78(%rsp), %xmm5
leaq 0x330a97(%rip), %rdi    # 0x44974d
movb $0x6, %al
callq 0x111080
jmp 0x118cbf
movsd 0xc78(%rsp), %xmm0
movsd 0xc70(%rsp), %xmm1
movsd 0xc60(%rsp), %xmm2
movsd 0xc58(%rsp), %xmm3
movsd 0xc68(%rsp), %xmm4
movsd 0x70(%rsp), %xmm5
leaq 0x330a8b(%rip), %rdi    # 0x449784
movb $0x6, %al
callq 0x111080
jmp 0x118d02
movsd 0x78(%rsp), %xmm0
movsd 0x70(%rsp), %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0xc78(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
movsd 0xc70(%rsp), %xmm0
movsd %xmm0, (%rsp)
movaps 0x32b2d4(%rip), %xmm1   # 0x444010
movsd 0xc58(%rsp), %xmm0
pxor %xmm1, %xmm0
movsd 0xc60(%rsp), %xmm1
mulsd %xmm1, %xmm0
callq 0x111130
movsd (%rsp), %xmm2
movsd 0x8(%rsp), %xmm1
movaps %xmm0, %xmm3
movsd 0x10(%rsp), %xmm0
mulsd %xmm3, %xmm2
subsd %xmm2, %xmm1
subsd %xmm1, %xmm0
movsd %xmm0, 0x68(%rsp)
movsd 0x68(%rsp), %xmm0
leaq 0x330a2d(%rip), %rdi    # 0x4497bb
movb $0x1, %al
callq 0x111080
jmp 0x118d97
leaq 0x1d0(%rsp), %rdi
callq 0x11a9e0
leaq 0xaf8(%rsp), %rdi
callq 0x11abe0
leaq 0xc30(%rsp), %rdi
callq 0x11ac20
leaq 0xc38(%rsp), %rdi
callq 0x111778
leaq 0xc98(%rsp), %rdi
callq 0x111778
addq $0xcb8, %rsp            # imm = 0xCB8
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xc97(%rsp), %rdi
callq 0x111760
jmp 0x1190bf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x1190a5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118e56
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xc10(%rsp), %rdi
callq 0x111778
leaq 0xc0f(%rsp), %rdi
callq 0x111760
jmp 0x119098
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118e9f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xbe8(%rsp), %rdi
callq 0x111778
leaq 0xbe7(%rsp), %rdi
callq 0x111760
jmp 0x119098
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118ee8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xbc0(%rsp), %rdi
callq 0x111778
leaq 0xbbf(%rsp), %rdi
callq 0x111760
jmp 0x119098
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118f31
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xb98(%rsp), %rdi
callq 0x111778
leaq 0xb97(%rsp), %rdi
callq 0x111760
jmp 0x119098
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118f7a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xb70(%rsp), %rdi
callq 0x111778
leaq 0xb6f(%rsp), %rdi
callq 0x111760
jmp 0x119098
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x118fc3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xb48(%rsp), %rdi
callq 0x111778
leaq 0xb47(%rsp), %rdi
callq 0x111760
jmp 0x119098
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x11900c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0xb20(%rsp), %rdi
callq 0x111778
leaq 0xb1f(%rsp), %rdi
callq 0x111760
jmp 0x119098
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x119098
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
jmp 0x11908b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0x80(%rsp), %rdi
callq 0x11a0c0
jmp 0x11908b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xc88(%rsp)
movl %eax, 0xc84(%rsp)
leaq 0x1d0(%rsp), %rdi
callq 0x11a9e0
leaq 0xaf8(%rsp), %rdi
callq 0x11abe0
leaq 0xc30(%rsp), %rdi
callq 0x11ac20
leaq 0xc38(%rsp), %rdi
callq 0x111778
leaq 0xc98(%rsp), %rdi
callq 0x111778
movq 0xc88(%rsp), %rdi
callq 0x111440
nopl (%rax)