// File: ArashPartow[P]exprtk/exprtk_simple_example_10.cpp
// Function: void newton_sqrt<double>()
void newton_sqrt()
{
   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;

   T x = T(0);

   symbol_table_t symbol_table;

   symbol_table.add_constants();
   symbol_table.add_variable("x",x);

   compositor_t compositor(symbol_table);

   compositor.add(
      function_t("newton_sqrt")
      .var("x")
      .expression
      (
         " switch                                                   "
         " {                                                        "
         "    case x < 0  : null;                                   "
         "    case x == 0 : 0;                                      "
         "    case x == 1 : 1;                                      "
         "    default:                                              "
         "    {                                                     "
         "       var remaining_itrs := 100;                         "
         "       var sqrt_x := x / 2;                               "
         "       repeat                                             "
         "          if (equal(sqrt_x * sqrt_x, x))                  "
         "             break[sqrt_x];                               "
         "          else                                            "
         "             sqrt_x := (1 / 2) * (sqrt_x + (x / sqrt_x)); "
         "       until ((remaining_itrs -= 1) <= 0);                "
         "    };                                                    "
         " }                                                        "
      ));

   const std::string expression_str = "newton_sqrt(x)";

   expression_t expression;
   expression.register_symbol_table(symbol_table);

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

   for (x = T(0); x < T(500); x += T(0.5))
   {
      const T result = expression.value();
      const T real   = std::sqrt(x);
      const T error  = std::abs(result - real);

      const bool err_in_bound = error <= exprtk::details::numeric::constant::pi;

      printf("sqrt(%6.2f) - Result: %15.13f\tReal: %15.13f\tError: %18.16f EIB: %c\n",
             x,
             result,
             real,
             error,
             err_in_bound ? 'T' : 'F');
   }
}

// Assembly:
subq $0x1668, %rsp           # imm = 0x1668
movq $0x0, 0x1660(%rsp)
leaq 0x1658(%rsp), %rdi
movq %rdi, 0x48(%rsp)
movl $0x1, %esi
callq 0x11b0c0
movq 0x48(%rsp), %rdi
callq 0x11b100
jmp 0x11a846
leaq 0x1627(%rsp), %rdi
movq %rdi, 0x40(%rsp)
callq 0x113650
movq 0x40(%rsp), %rdx
leaq 0x347c59(%rip), %rsi    # 0x4624bd
leaq 0x1628(%rsp), %rdi
callq 0x11a750
jmp 0x11a873
leaq 0x1658(%rsp), %rdi
leaq 0x1628(%rsp), %rsi
leaq 0x1660(%rsp), %rdx
xorl %ecx, %ecx
callq 0x11b160
jmp 0x11a894
leaq 0x1628(%rsp), %rdi
callq 0x113788
leaq 0x1627(%rsp), %rdi
callq 0x113770
leaq 0xc38(%rsp), %rdi
leaq 0x1658(%rsp), %rsi
callq 0x11b210
jmp 0x11a8c5
leaq 0xb87(%rsp), %rdi
movq %rdi, 0x38(%rsp)
callq 0x113650
movq 0x38(%rsp), %rdx
leaq 0x347c7d(%rip), %rsi    # 0x462560
leaq 0xb88(%rsp), %rdi
callq 0x11a750
jmp 0x11a8f2
leaq 0xba8(%rsp), %rdi
leaq 0xb88(%rsp), %rsi
callq 0x11b400
jmp 0x11a909
leaq 0xb5f(%rsp), %rdi
movq %rdi, 0x30(%rsp)
callq 0x113650
movq 0x30(%rsp), %rdx
leaq 0x347b96(%rip), %rsi    # 0x4624bd
leaq 0xb60(%rsp), %rdi
callq 0x11a750
jmp 0x11a936
leaq 0xba8(%rsp), %rdi
leaq 0xb60(%rsp), %rsi
callq 0x11b480
movq %rax, 0x28(%rsp)
jmp 0x11a952
leaq 0xb37(%rsp), %rdi
movq %rdi, 0x20(%rsp)
callq 0x113650
movq 0x20(%rsp), %rdx
leaq 0x347bfc(%rip), %rsi    # 0x46256c
leaq 0xb38(%rsp), %rdi
callq 0x11a750
jmp 0x11a97f
movq 0x28(%rsp), %rdi
leaq 0xb38(%rsp), %rsi
callq 0x11b4b0
movq %rax, 0x18(%rsp)
jmp 0x11a998
movq 0x18(%rsp), %rsi
leaq 0xc38(%rsp), %rdi
xorl %edx, %edx
callq 0x11b3b0
jmp 0x11a9ae
leaq 0xb38(%rsp), %rdi
callq 0x113788
leaq 0xb37(%rsp), %rdi
callq 0x113770
leaq 0xb60(%rsp), %rdi
callq 0x113788
leaq 0xb5f(%rsp), %rdi
callq 0x113770
leaq 0xba8(%rsp), %rdi
callq 0x11b4e0
leaq 0xb88(%rsp), %rdi
callq 0x113788
leaq 0xb87(%rsp), %rdi
callq 0x113770
leaq 0xb0f(%rsp), %rdi
movq %rdi, 0x10(%rsp)
callq 0x113650
movq 0x10(%rsp), %rdx
leaq 0x347f20(%rip), %rsi    # 0x462947
leaq 0xb10(%rsp), %rdi
callq 0x11a750
jmp 0x11aa36
leaq 0xb0f(%rsp), %rdi
callq 0x113770
leaq 0xae8(%rsp), %rdi
callq 0x11b520
jmp 0x11aa52
leaq 0xae8(%rsp), %rdi
leaq 0x1658(%rsp), %rsi
callq 0x11b5d0
jmp 0x11aa69
leaq 0x70(%rsp), %rdi
movl $0x7f, %esi
callq 0x11b680
jmp 0x11aa7a
leaq 0x1c0(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x11b7b0
jmp 0x11aa8e
leaq 0x70(%rsp), %rdi
callq 0x11bfe0
leaq 0x1c0(%rsp), %rdi
leaq 0xb10(%rsp), %rsi
leaq 0xae8(%rsp), %rdx
callq 0x11c050
jmp 0x11aab7
xorps %xmm0, %xmm0
movsd %xmm0, 0x1660(%rsp)
movsd 0x34253d(%rip), %xmm0   # 0x45d008
ucomisd 0x1660(%rsp), %xmm0
jbe 0x11ad91
leaq 0xae8(%rsp), %rdi
callq 0x11c8e0
movsd %xmm0, 0x8(%rsp)
jmp 0x11aaef
movsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x68(%rsp)
movsd 0x1660(%rsp), %xmm0
callq 0x113370
movsd %xmm0, 0x60(%rsp)
movsd 0x68(%rsp), %xmm0
movsd 0x60(%rsp), %xmm1
subsd %xmm1, %xmm0
callq 0x11c900
movsd %xmm0, (%rsp)
jmp 0x11ab2b
movsd (%rsp), %xmm0
movsd %xmm0, 0x58(%rsp)
movsd 0x58(%rsp), %xmm1
movsd 0x3424cc(%rip), %xmm0   # 0x45d010
ucomisd %xmm1, %xmm0
setae 0x57(%rsp)
movsd 0x1660(%rsp), %xmm0
movsd 0x68(%rsp), %xmm1
movsd 0x60(%rsp), %xmm2
movsd 0x58(%rsp), %xmm3
movb 0x57(%rsp), %al
testb $0x1, %al
movl $0x54, %eax
movl $0x46, %esi
cmovnel %eax, %esi
leaq 0x347dd4(%rip), %rdi    # 0x462956
movb $0x4, %al
callq 0x113080
jmp 0x11ab8b
jmp 0x11ab8d
movsd 0x342483(%rip), %xmm0   # 0x45d018
addsd 0x1660(%rsp), %xmm0
movsd %xmm0, 0x1660(%rsp)
jmp 0x11aac3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
jmp 0x11ae01
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
jmp 0x11abfc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
leaq 0x1628(%rsp), %rdi
callq 0x113788
leaq 0x1627(%rsp), %rdi
callq 0x113770
jmp 0x11ae01
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
jmp 0x11ace4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
jmp 0x11acd7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
jmp 0x11acbd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
jmp 0x11acb0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
jmp 0x11aca3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
leaq 0xb38(%rsp), %rdi
callq 0x113788
leaq 0xb37(%rsp), %rdi
callq 0x113770
leaq 0xb60(%rsp), %rdi
callq 0x113788
leaq 0xb5f(%rsp), %rdi
callq 0x113770
leaq 0xba8(%rsp), %rdi
callq 0x11b4e0
leaq 0xb88(%rsp), %rdi
callq 0x113788
leaq 0xb87(%rsp), %rdi
callq 0x113770
jmp 0x11adf4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
leaq 0xb0f(%rsp), %rdi
callq 0x113770
jmp 0x11adf4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
jmp 0x11ade7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
jmp 0x11adda
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
leaq 0x70(%rsp), %rdi
callq 0x11bfe0
jmp 0x11adda
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1650(%rsp)
movl %eax, 0x164c(%rsp)
leaq 0x1c0(%rsp), %rdi
callq 0x11c920
jmp 0x11adda
leaq 0x1c0(%rsp), %rdi
callq 0x11c920
leaq 0xae8(%rsp), %rdi
callq 0x11cb20
leaq 0xb10(%rsp), %rdi
callq 0x113788
leaq 0xc38(%rsp), %rdi
callq 0x11cb60
leaq 0x1658(%rsp), %rdi
callq 0x11cbf0
addq $0x1668, %rsp           # imm = 0x1668
retq
leaq 0xae8(%rsp), %rdi
callq 0x11cb20
leaq 0xb10(%rsp), %rdi
callq 0x113788
leaq 0xc38(%rsp), %rdi
callq 0x11cb60
leaq 0x1658(%rsp), %rdi
callq 0x11cbf0
movq 0x1650(%rsp), %rdi
callq 0x113440
nopl (%rax,%rax)