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

   const std::string european_option_binomial_model_program =
      " var dt     := t / n;                                              "
      " var z      := exp(r * dt);                                        "
      " var z_inv  := 1 / z;                                              "
      " var u      := exp(v * sqrt(dt));                                  "
      " var p_up   := (z * u - 1) / (u^2 - 1);                            "
      " var p_down := 1 - p_up;                                           "
      "                                                                   "
      " var option_price[n + 1] := [0];                                   "
      "                                                                   "
      " for (var i := 0; i <= n; i += 1)                                  "
      " {                                                                 "
      "    var base_price := s * u^(n - 2i);                              "
      "                                                                   "
      "    option_price[i] :=                                             "
      "       switch                                                      "
      "       {                                                           "
      "          case callput_flag == 'call' : max(base_price - k, 0);    "
      "          case callput_flag == 'put'  : max(k - base_price, 0);    "
      "       };                                                          "
      " };                                                                "
      "                                                                   "
      " for (var j := n - 1; j >= 0; j -= 1)                              "
      " {                                                                 "
      "    for (var i := 0; i <= j; i += 1)                               "
      "    {                                                              "
      "       option_price[i] := z_inv *                                  "
      "          (p_up * option_price[i] + p_down * option_price[i + 1]); "
      "    }                                                              "
      " };                                                                "
      "                                                                   "
      " option_price[0];                                                  ";

   T s = T( 100.00); // Spot / Stock / Underlying / Base price
   T k = T( 110.00); // Strike price
   T v = T(   0.30); // Volatility
   T t = T(   2.22); // Years to maturity
   T r = T(   0.05); // Risk free rate
   T n = T(1000.00); // Number of time steps

   std::string callput_flag;

   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("n",n);
   symbol_table.add_stringvar("callput_flag",callput_flag);

   expression_t expression;
   expression.register_symbol_table(symbol_table);

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

   callput_flag = "call";

   const T binomial_call_option_price = expression.value();

   callput_flag = "put";

   const T binomial_put_option_price = expression.value();

   printf("BinomialPrice(call, %5.3f, %5.3f, %5.3f, %5.3f, %5.3f) = %22.18f\n",
          s, k, t, r, v,
          binomial_call_option_price);

   printf("BinomialPrice(put , %5.3f, %5.3f, %5.3f, %5.3f, %5.3f) = %22.18f\n",
          s, k, t, r, v,
          binomial_put_option_price);

   const T put_call_parity_diff =
      (binomial_call_option_price - binomial_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 $0xb30, %rsp            # imm = 0xB30
leaq 0x12adff(%rip), %rsi    # 0x23b101
leaq 0x98(%rsp), %rdi
leaq 0x208(%rsp), %rdx
callq 0x1102b8
movabsq $0x4059000000000000, %rax # imm = 0x4059000000000000
movq %rax, 0x38(%rsp)
movabsq $0x405b800000000000, %rax # imm = 0x405B800000000000
movq %rax, 0x30(%rsp)
movabsq $0x3fd3333333333333, %rax # imm = 0x3FD3333333333333
movq %rax, 0x40(%rsp)
movabsq $0x4001c28f5c28f5c3, %rax # imm = 0x4001C28F5C28F5C3
movq %rax, 0x28(%rsp)
movabsq $0x3fa999999999999a, %rax # imm = 0x3FA999999999999A
movq %rax, 0x20(%rsp)
movabsq $0x408f400000000000, %rax # imm = 0x408F400000000000
movq %rax, 0x50(%rsp)
leaq 0x88(%rsp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
leaq 0x8(%rsp), %rdi
pushq $0x1
popq %rsi
callq 0x110856
leaq 0x12ac18(%rip), %rsi    # 0x23afb1
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x1102b8
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x38(%rsp), %rdx
xorl %ecx, %ecx
callq 0x11087a
leaq 0x208(%rsp), %rdi
callq 0x10e5b8
leaq 0x12ab69(%rip), %rsi    # 0x23af44
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x1102b8
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x30(%rsp), %rdx
xorl %ecx, %ecx
callq 0x11087a
leaq 0x208(%rsp), %rdi
callq 0x10e5b8
leaq 0x12bc5f(%rip), %rsi    # 0x23c07c
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x1102b8
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x28(%rsp), %rdx
xorl %ecx, %ecx
callq 0x11087a
leaq 0x208(%rsp), %rdi
callq 0x10e5b8
leaq 0x12ab3d(%rip), %rsi    # 0x23af9c
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x1102b8
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x20(%rsp), %rdx
xorl %ecx, %ecx
callq 0x11087a
leaq 0x208(%rsp), %rdi
callq 0x10e5b8
leaq 0x12b47e(%rip), %rsi    # 0x23b91f
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x1102b8
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x40(%rsp), %rdx
xorl %ecx, %ecx
callq 0x11087a
leaq 0x208(%rsp), %rdi
callq 0x10e5b8
leaq 0x12aae9(%rip), %rsi    # 0x23afcc
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x1102b8
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x50(%rsp), %rdx
callq 0x1108e6
leaq 0x208(%rsp), %rdi
callq 0x10e5b8
leaq 0x12b3fe(%rip), %rsi    # 0x23b921
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rdx
callq 0x1102b8
leaq 0x8(%rsp), %rdi
leaq 0x208(%rsp), %rsi
leaq 0x78(%rsp), %rdx
xorl %ecx, %ecx
callq 0x110962
leaq 0x208(%rsp), %rdi
callq 0x10e5b8
leaq 0x58(%rsp), %rdi
callq 0x1109d4
leaq 0x58(%rsp), %rdi
leaq 0x8(%rsp), %rsi
callq 0x110a34
leaq 0xb8(%rsp), %rdi
pushq $0x7f
popq %rsi
callq 0x110a90
leaq 0x208(%rsp), %rdi
leaq 0xb8(%rsp), %rsi
callq 0x110ba0
leaq 0xb8(%rsp), %rdi
callq 0x1111b8
leaq 0x208(%rsp), %rdi
leaq 0x98(%rsp), %rsi
leaq 0x58(%rsp), %rdx
callq 0x111200
leaq 0x12ed15(%rip), %rsi    # 0x23f2df
leaq 0x78(%rsp), %rdi
callq 0x10e570
movq 0x58(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movsd %xmm0, 0x18(%rsp)
leaq 0x12b33e(%rip), %rsi    # 0x23b92e
leaq 0x78(%rsp), %rdi
callq 0x10e570
movq 0x58(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movsd %xmm0, 0x10(%rsp)
movsd 0x38(%rsp), %xmm0
movsd 0x30(%rsp), %xmm1
movsd 0x28(%rsp), %xmm2
movsd 0x20(%rsp), %xmm3
movsd 0x40(%rsp), %xmm4
leaq 0x12b2fe(%rip), %rdi    # 0x23b932
movsd 0x18(%rsp), %xmm5
movb $0x6, %al
callq 0x10e060
movsd 0x38(%rsp), %xmm0
movsd 0x30(%rsp), %xmm1
movsd 0x28(%rsp), %xmm2
movsd 0x20(%rsp), %xmm3
movsd 0x40(%rsp), %xmm4
leaq 0x12b30e(%rip), %rdi    # 0x23b974
movsd 0x10(%rsp), %xmm5
movb $0x6, %al
callq 0x10e060
movsd 0x18(%rsp), %xmm0
subsd 0x10(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x38(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0x30(%rsp), %xmm0
movsd %xmm0, 0x48(%rsp)
movsd 0x20(%rsp), %xmm0
xorpd 0x125965(%rip), %xmm0   # 0x236010
mulsd 0x28(%rsp), %xmm0
callq 0x10e0d0
mulsd 0x48(%rsp), %xmm0
movsd 0x10(%rsp), %xmm1
subsd %xmm0, %xmm1
movsd 0x18(%rsp), %xmm0
subsd %xmm1, %xmm0
leaq 0x12b2df(%rip), %rdi    # 0x23b9b6
movb $0x1, %al
callq 0x10e060
leaq 0x208(%rsp), %rdi
callq 0x111682
leaq 0x58(%rsp), %rdi
callq 0x1117bc
leaq 0x8(%rsp), %rdi
callq 0x1117d2
leaq 0x78(%rsp), %rdi
callq 0x10e5b8
leaq 0x98(%rsp), %rdi
callq 0x10e5b8
addq $0xb30, %rsp            # imm = 0xB30
popq %rbx
retq
jmp 0x110772
movq %rax, %rbx
leaq 0xb8(%rsp), %rdi
callq 0x1111b8
jmp 0x110782
jmp 0x110735
movq %rax, %rbx
jmp 0x110782
jmp 0x110766
jmp 0x110754
jmp 0x110766
jmp 0x110754
jmp 0x110766
jmp 0x110754
jmp 0x110766
jmp 0x110754
jmp 0x110766
jmp 0x110754
jmp 0x110766
jmp 0x110754
jmp 0x110766
movq %rax, %rbx
leaq 0x208(%rsp), %rdi
callq 0x10e5b8
jmp 0x11078c
movq %rax, %rbx
jmp 0x11078c
movq %rax, %rbx
jmp 0x110796
jmp 0x110772
movq %rax, %rbx
leaq 0x208(%rsp), %rdi
callq 0x111682
leaq 0x58(%rsp), %rdi
callq 0x1117bc
leaq 0x8(%rsp), %rdi
callq 0x1117d2
leaq 0x78(%rsp), %rdi
callq 0x10e5b8
leaq 0x98(%rsp), %rdi
callq 0x10e5b8
movq %rbx, %rdi
callq 0x10e310