// File: /workspace/github_cpp_makefile_star2_O2/ArashPartow[P]exprtk/exprtk_simple_example_22.cpp
// Function: void compute_european_option_implied_volatility<double>()
void compute_european_option_implied_volatility()
{
   typedef exprtk::symbol_table<T>         symbol_table_t;
   typedef exprtk::expression<T>           expression_t;
   typedef exprtk::parser<T>               parser_t;
   typedef exprtk::function_compositor<T>  compositor_t;
   typedef typename compositor_t::function function_t;

   const std::string option_implied_volatility_program =
      " const var epsilon   := 0.0000001;                               "
      " const var max_iters := 1000;                                    "
      "                                                                 "
      " var v   := 0.5; /* Initial volatility guess */                  "
      " var itr := 0;                                                   "
      "                                                                 "
      " while ((itr += 1) <= max_iters)                                 "
      " {                                                               "
      "    var price :=                                                 "
      "       switch                                                    "
      "       {                                                         "
      "          case callput_flag == 'call' : bsm_call(s, k, r, t, v); "
      "          case callput_flag == 'put'  : bsm_put (s, k, r, t, v); "
      "       };                                                        "
      "                                                                 "
      "    var price_diff := price - target_price;                      "
      "                                                                 "
      "    if (abs(price_diff) <= epsilon)                              "
      "    {                                                            "
      "       break;                                                    "
      "    };                                                           "
      "                                                                 "
      "    var vega := bsm_vega(s, k, r, t, v);                         "
      "                                                                 "
      "    if (vega < epsilon)                                          "
      "    {                                                            "
      "       itr := max_iters + 1;                                     "
      "       break;                                                    "
      "    };                                                           "
      "                                                                 "
      "    v -= price_diff / vega;                                      "
      " };                                                              "
      "                                                                 "
      " itr <= max_iters ? v : null;                                    ";

   T s            = T(100.00); // Spot / Stock / Underlying / Base price
   T k            = T(110.00); // Strike price
   T t            = T(  2.22); // Years to maturity
   T r            = T(  0.05); // Risk free rate
   T target_price = T(  0.00);

   std::string callput_flag;

   symbol_table_t symbol_table(symbol_table_t::e_immutable);
   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_stringvar("callput_flag",callput_flag);
   symbol_table.add_variable ("target_price",target_price);
   symbol_table.add_pi();

   compositor_t compositor(symbol_table);

   compositor.add(
      function_t("bsm_call")
      .vars("s", "k", "r", "t", "v")
      .expression
      (
         " var d1 := (log(s / k) + (r + v^2 / 2) * t) / (v * sqrt(t)); "
         " var d2 := d1 - v * sqrt(t);                                 "
         " s * ncdf(d1) - k * exp(-r * t) * ncdf(d2);                  "
      ));

   compositor.add(
      function_t("bsm_put")
      .vars("s", "k", "r", "t", "v")
      .expression
      (
         " var d1 := (log(s / k) + (r + v^2 / 2) * t) / (v * sqrt(t)); "
         " var d2 := d1 - v * sqrt(t);                                 "
         " k * exp(-r * t) * ncdf(-d2) - s * ncdf(-d1);                "
      ));

   compositor.add(
      function_t("bsm_vega")
      .vars("s", "k", "r", "t", "v")
      .expression
      (
         " var d1 := (log(s / k) + (r + v^2 / 2) * t) / (v * sqrt(t)); "
         " s * exp(-d1^2 / 2) / sqrt(2pi) * sqrt(t);                   "
      ));

   expression_t expression;
   expression.register_symbol_table(symbol_table);

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

   {
      callput_flag = "call";
      target_price = T(18.339502);

      const T call_option_implied_vol = expression.value();

      printf("Call Option(s: %5.3f, k: %5.3f, t: %5.3f, r: %5.3f) "
             "@ $%8.6f Implied volatility = %10.8f\n",
             s, k, t, r, target_price, call_option_implied_vol);
   }

   {
      callput_flag = "put";
      target_price = T(16.782764);

      const T put_option_implied_vol = expression.value();

      printf("Put  Option(s: %5.3f, k: %5.3f, t: %5.3f, r: %5.3f) "
             "@ $%8.6f Implied volatility = %10.8f\n",
             s, k, t, r, target_price, put_option_implied_vol);
   }
}

// Assembly:
pushq %rbx
subq $0x15a0, %rsp           # imm = 0x15A0
leaq 0x131e0b(%rip), %rsi    # 0x24411d
leaq 0x120(%rsp), %rdi
leaq 0x290(%rsp), %rdx
callq 0x1122c8
movabsq $0x4059000000000000, %rax # imm = 0x4059000000000000
movq %rax, 0x58(%rsp)
movabsq $0x405b800000000000, %rax # imm = 0x405B800000000000
movq %rax, 0x50(%rsp)
movabsq $0x4001c28f5c28f5c3, %rax # imm = 0x4001C28F5C28F5C3
movq %rax, 0x48(%rsp)
andq $0x0, 0x18(%rsp)
movabsq $0x3fa999999999999a, %rax # imm = 0x3FA999999999999A
movq %rax, 0x40(%rsp)
leaq 0x110(%rsp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
leaq 0x10(%rsp), %rdi
pushq $0x2
popq %rsi
callq 0x112d3a
leaq 0x131c3c(%rip), %rsi    # 0x243fcd
leaq 0x290(%rsp), %rdi
leaq 0xc78(%rsp), %rdx
callq 0x1122c8
leaq 0x10(%rsp), %rdi
leaq 0x290(%rsp), %rsi
leaq 0x58(%rsp), %rdx
xorl %ecx, %ecx
callq 0x112d5e
leaq 0x290(%rsp), %rdi
callq 0x1105c8
leaq 0x131b8d(%rip), %rsi    # 0x243f60
leaq 0x290(%rsp), %rdi
leaq 0xc78(%rsp), %rdx
callq 0x1122c8
leaq 0x10(%rsp), %rdi
leaq 0x290(%rsp), %rsi
leaq 0x50(%rsp), %rdx
xorl %ecx, %ecx
callq 0x112d5e
leaq 0x290(%rsp), %rdi
callq 0x1105c8
leaq 0x13300c(%rip), %rsi    # 0x245421
leaq 0x290(%rsp), %rdi
leaq 0xc78(%rsp), %rdx
callq 0x1122c8
leaq 0x10(%rsp), %rdi
leaq 0x290(%rsp), %rsi
leaq 0x48(%rsp), %rdx
xorl %ecx, %ecx
callq 0x112d5e
leaq 0x290(%rsp), %rdi
callq 0x1105c8
leaq 0x131b61(%rip), %rsi    # 0x243fb8
leaq 0x290(%rsp), %rdi
leaq 0xc78(%rsp), %rdx
callq 0x1122c8
leaq 0x10(%rsp), %rdi
leaq 0x290(%rsp), %rsi
leaq 0x40(%rsp), %rdx
xorl %ecx, %ecx
callq 0x112d5e
leaq 0x290(%rsp), %rdi
callq 0x1105c8
leaq 0x132527(%rip), %rsi    # 0x2449c0
leaq 0x290(%rsp), %rdi
leaq 0xc78(%rsp), %rdx
callq 0x1122c8
leaq 0x10(%rsp), %rdi
leaq 0x290(%rsp), %rsi
leaq 0x100(%rsp), %rdx
xorl %ecx, %ecx
callq 0x112dca
leaq 0x290(%rsp), %rdi
callq 0x1105c8
leaq 0x1324ef(%rip), %rsi    # 0x2449cd
leaq 0x290(%rsp), %rdi
leaq 0xc78(%rsp), %rdx
callq 0x1122c8
leaq 0x10(%rsp), %rdi
leaq 0x290(%rsp), %rsi
leaq 0x18(%rsp), %rdx
xorl %ecx, %ecx
callq 0x112d5e
leaq 0x290(%rsp), %rdi
callq 0x1105c8
leaq 0x10(%rsp), %rdi
callq 0x112e3c
leaq 0x290(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x112ed6
leaq 0x13249e(%rip), %rsi    # 0x2449da
leaq 0x140(%rsp), %rdi
leaq 0xf(%rsp), %rdx
callq 0x1122c8
leaq 0xc78(%rsp), %rdi
leaq 0x140(%rsp), %rsi
callq 0x112ff4
leaq 0x131a63(%rip), %rsi    # 0x243fcd
leaq 0x20(%rsp), %rdi
leaq 0xe(%rsp), %rdx
callq 0x1122c8
leaq 0x1319e0(%rip), %rsi    # 0x243f60
leaq 0xe0(%rsp), %rdi
leaq 0xd(%rsp), %rdx
callq 0x1122c8
leaq 0x131a1f(%rip), %rsi    # 0x243fb8
leaq 0xc0(%rsp), %rdi
leaq 0xc(%rsp), %rdx
callq 0x1122c8
leaq 0x132e6f(%rip), %rsi    # 0x245421
leaq 0xa0(%rsp), %rdi
leaq 0xb(%rsp), %rdx
callq 0x1122c8
leaq 0x132418(%rip), %rsi    # 0x2449e3
leaq 0x80(%rsp), %rdi
leaq 0xa(%rsp), %rdx
callq 0x1122c8
leaq 0xc78(%rsp), %rdi
leaq 0x20(%rsp), %rsi
leaq 0xe0(%rsp), %rdx
leaq 0xc0(%rsp), %rcx
leaq 0xa0(%rsp), %r8
leaq 0x80(%rsp), %r9
callq 0x113040
movq %rax, %rbx
leaq 0x1323cc(%rip), %rsi    # 0x2449e5
leaq 0x60(%rsp), %rdi
leaq 0x9(%rsp), %rdx
callq 0x1122c8
leaq 0x20(%rbx), %rdi
leaq 0x60(%rsp), %rsi
callq 0x110550
leaq 0x290(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x112fe4
leaq 0x60(%rsp), %rdi
callq 0x1105c8
leaq 0x80(%rsp), %rdi
callq 0x1105c8
leaq 0xa0(%rsp), %rdi
callq 0x1105c8
leaq 0xc0(%rsp), %rdi
callq 0x1105c8
leaq 0xe0(%rsp), %rdi
callq 0x1105c8
leaq 0x20(%rsp), %rdi
callq 0x1105c8
leaq 0xc78(%rsp), %rdi
callq 0x1130a4
leaq 0x140(%rsp), %rdi
callq 0x1105c8
leaq 0x1323ec(%rip), %rsi    # 0x244a9d
leaq 0x140(%rsp), %rdi
leaq 0xf(%rsp), %rdx
callq 0x1122c8
leaq 0xc78(%rsp), %rdi
leaq 0x140(%rsp), %rsi
callq 0x112ff4
leaq 0x1318ee(%rip), %rsi    # 0x243fcd
leaq 0x20(%rsp), %rdi
leaq 0xe(%rsp), %rdx
callq 0x1122c8
leaq 0x13186b(%rip), %rsi    # 0x243f60
leaq 0xe0(%rsp), %rdi
leaq 0xd(%rsp), %rdx
callq 0x1122c8
leaq 0x1318aa(%rip), %rsi    # 0x243fb8
leaq 0xc0(%rsp), %rdi
leaq 0xc(%rsp), %rdx
callq 0x1122c8
leaq 0x132cfa(%rip), %rsi    # 0x245421
leaq 0xa0(%rsp), %rdi
leaq 0xb(%rsp), %rdx
callq 0x1122c8
leaq 0x1322a3(%rip), %rsi    # 0x2449e3
leaq 0x80(%rsp), %rdi
leaq 0xa(%rsp), %rdx
callq 0x1122c8
leaq 0xc78(%rsp), %rdi
leaq 0x20(%rsp), %rsi
leaq 0xe0(%rsp), %rdx
leaq 0xc0(%rsp), %rcx
leaq 0xa0(%rsp), %r8
leaq 0x80(%rsp), %r9
callq 0x113040
movq %rax, %rbx
leaq 0x132317(%rip), %rsi    # 0x244aa5
leaq 0x60(%rsp), %rdi
leaq 0x9(%rsp), %rdx
callq 0x1122c8
leaq 0x20(%rbx), %rdi
leaq 0x60(%rsp), %rsi
callq 0x110550
leaq 0x290(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x112fe4
leaq 0x60(%rsp), %rdi
callq 0x1105c8
leaq 0x80(%rsp), %rdi
callq 0x1105c8
leaq 0xa0(%rsp), %rdi
callq 0x1105c8
leaq 0xc0(%rsp), %rdi
callq 0x1105c8
leaq 0xe0(%rsp), %rdi
callq 0x1105c8
leaq 0x20(%rsp), %rdi
callq 0x1105c8
leaq 0xc78(%rsp), %rdi
callq 0x1130a4
leaq 0x140(%rsp), %rdi
callq 0x1105c8
leaq 0x132337(%rip), %rsi    # 0x244b5d
leaq 0x140(%rsp), %rdi
leaq 0xf(%rsp), %rdx
callq 0x1122c8
leaq 0xc78(%rsp), %rdi
leaq 0x140(%rsp), %rsi
callq 0x112ff4
leaq 0x131779(%rip), %rsi    # 0x243fcd
leaq 0x20(%rsp), %rdi
leaq 0xe(%rsp), %rdx
callq 0x1122c8
leaq 0x1316f6(%rip), %rsi    # 0x243f60
leaq 0xe0(%rsp), %rdi
leaq 0xd(%rsp), %rdx
callq 0x1122c8
leaq 0x131735(%rip), %rsi    # 0x243fb8
leaq 0xc0(%rsp), %rdi
leaq 0xc(%rsp), %rdx
callq 0x1122c8
leaq 0x132b85(%rip), %rsi    # 0x245421
leaq 0xa0(%rsp), %rdi
leaq 0xb(%rsp), %rdx
callq 0x1122c8
leaq 0x13212e(%rip), %rsi    # 0x2449e3
leaq 0x80(%rsp), %rdi
leaq 0xa(%rsp), %rdx
callq 0x1122c8
leaq 0xc78(%rsp), %rdi
leaq 0x20(%rsp), %rsi
leaq 0xe0(%rsp), %rdx
leaq 0xc0(%rsp), %rcx
leaq 0xa0(%rsp), %r8
leaq 0x80(%rsp), %r9
callq 0x113040
movq %rax, %rbx
leaq 0x132263(%rip), %rsi    # 0x244b66
leaq 0x60(%rsp), %rdi
leaq 0x9(%rsp), %rdx
callq 0x1122c8
leaq 0x20(%rbx), %rdi
leaq 0x60(%rsp), %rsi
callq 0x110550
leaq 0x290(%rsp), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x112fe4
leaq 0x60(%rsp), %rdi
callq 0x1105c8
leaq 0x80(%rsp), %rdi
callq 0x1105c8
leaq 0xa0(%rsp), %rdi
callq 0x1105c8
leaq 0xc0(%rsp), %rdi
callq 0x1105c8
leaq 0xe0(%rsp), %rdi
callq 0x1105c8
leaq 0x20(%rsp), %rdi
callq 0x1105c8
leaq 0xc78(%rsp), %rdi
callq 0x1130a4
leaq 0x140(%rsp), %rdi
callq 0x1105c8
leaq 0x20(%rsp), %rdi
callq 0x1130c4
leaq 0x20(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x113124
leaq 0x140(%rsp), %rdi
pushq $0x7f
popq %rsi
callq 0x113180
leaq 0xc78(%rsp), %rdi
leaq 0x140(%rsp), %rsi
callq 0x113290
leaq 0x140(%rsp), %rdi
callq 0x1138a8
leaq 0xc78(%rsp), %rdi
leaq 0x120(%rsp), %rsi
leaq 0x20(%rsp), %rdx
callq 0x1138f0
leaq 0x135c58(%rip), %rsi    # 0x248658
leaq 0x100(%rsp), %rdi
callq 0x110580
movabsq $0x403256e99a62ed35, %rax # imm = 0x403256E99A62ED35
movq %rax, 0x18(%rsp)
movq 0x20(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movaps %xmm0, %xmm5
movsd 0x58(%rsp), %xmm0
movsd 0x50(%rsp), %xmm1
movsd 0x48(%rsp), %xmm2
movsd 0x40(%rsp), %xmm3
movsd 0x18(%rsp), %xmm4
leaq 0x13218e(%rip), %rdi    # 0x244be1
movb $0x6, %al
callq 0x110060
leaq 0x132040(%rip), %rsi    # 0x244aa1
leaq 0x100(%rsp), %rdi
callq 0x110580
movabsq $0x4030c86338b47c74, %rax # imm = 0x4030C86338B47C74
movq %rax, 0x18(%rsp)
movq 0x20(%rsp), %rax
movq 0x8(%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movaps %xmm0, %xmm5
movsd 0x58(%rsp), %xmm0
movsd 0x50(%rsp), %xmm1
movsd 0x48(%rsp), %xmm2
movsd 0x40(%rsp), %xmm3
movsd 0x18(%rsp), %xmm4
leaq 0x132187(%rip), %rdi    # 0x244c3b
movb $0x6, %al
callq 0x110060
leaq 0xc78(%rsp), %rdi
callq 0x113d72
leaq 0x20(%rsp), %rdi
callq 0x113eac
leaq 0x290(%rsp), %rdi
callq 0x113ec2
leaq 0x10(%rsp), %rdi
callq 0x113f16
leaq 0x100(%rsp), %rdi
callq 0x1105c8
leaq 0x120(%rsp), %rdi
callq 0x1105c8
addq $0x15a0, %rsp           # imm = 0x15A0
popq %rbx
retq
jmp 0x112c45
jmp 0x112c45
movq %rax, %rbx
leaq 0x140(%rsp), %rdi
callq 0x1138a8
jmp 0x112c55
jmp 0x112b2d
movq %rax, %rbx
jmp 0x112c55
jmp 0x112b95
jmp 0x112b5d
jmp 0x112b5d
jmp 0x112b65
jmp 0x112b6d
jmp 0x112b75
jmp 0x112b7d
jmp 0x112b85
jmp 0x112b8d
jmp 0x112b95
jmp 0x112b5d
jmp 0x112b5d
jmp 0x112b65
jmp 0x112b6d
jmp 0x112b75
jmp 0x112b7d
jmp 0x112b85
jmp 0x112b8d
jmp 0x112b95
jmp 0x112b5d
movq %rax, %rbx
jmp 0x112beb
movq %rax, %rbx
jmp 0x112bf8
movq %rax, %rbx
jmp 0x112c05
movq %rax, %rbx
jmp 0x112c12
movq %rax, %rbx
jmp 0x112c1f
movq %rax, %rbx
jmp 0x112c29
movq %rax, %rbx
jmp 0x112c36
movq %rax, %rbx
jmp 0x112c5f
jmp 0x112bca
jmp 0x112bca
jmp 0x112bb5
jmp 0x112bca
jmp 0x112bb5
jmp 0x112bca
jmp 0x112bb5
jmp 0x112bca
jmp 0x112bb5
jmp 0x112bca
jmp 0x112bb5
jmp 0x112bca
movq %rax, %rbx
leaq 0x290(%rsp), %rdi
callq 0x1105c8
jmp 0x112c6c
movq %rax, %rbx
jmp 0x112c6c
movq %rax, %rbx
jmp 0x112c76
jmp 0x112bde
jmp 0x112bde
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
callq 0x1105c8
leaq 0x80(%rsp), %rdi
callq 0x1105c8
leaq 0xa0(%rsp), %rdi
callq 0x1105c8
leaq 0xc0(%rsp), %rdi
callq 0x1105c8
leaq 0xe0(%rsp), %rdi
callq 0x1105c8
leaq 0x20(%rsp), %rdi
callq 0x1105c8
leaq 0xc78(%rsp), %rdi
callq 0x1130a4
leaq 0x140(%rsp), %rdi
callq 0x1105c8
jmp 0x112c5f
movq %rax, %rbx
leaq 0xc78(%rsp), %rdi
callq 0x113d72
leaq 0x20(%rsp), %rdi
callq 0x113eac
leaq 0x290(%rsp), %rdi
callq 0x113ec2
leaq 0x10(%rsp), %rdi
callq 0x113f16
leaq 0x100(%rsp), %rdi
callq 0x1105c8
leaq 0x120(%rsp), %rdi
callq 0x1105c8
movq %rbx, %rdi
callq 0x110310