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

   // Form: n = p*q where p,q are prime
   T composites[] =
   {
       199203677,  779234623,  843093203,  883543291, 1197162971, 1282615157, 1368190717,
      1552390397, 1765737859, 1800091571, 1878769589, 1993904873, 2257133471, 2520523529,
      2579094799, 2853450949, 2935025369, 3095780533, 3164132249, 3408963511, 4260042859,
      4608613981, 4654875857, 5085931997, 6064982771, 7278175081, 7289187463, 9206112101
   };

   exprtk::rtl::io::println<T> println;

   symbol_table_t symbol_table;

   symbol_table.add_vector  ("composites", composites);
   symbol_table.add_function("println"   , println   );

   compositor_t compositor(symbol_table);

   compositor.add(function_t()
      .name("is_square")
      .var("x")
      .expression
      (
         " var s := sqrt(x);  "
         " var t := trunc(s); "
         " (s - t) == 0;      "
      ));

   compositor.add(function_t()
      .name("fermat")
      .var("n")
      .expression
      (
         " if (n == 0)                     "
         " {                               "
         "    return [0];                  "
         " }                               "
         " else if ((n % 2) == 0)          "
         " {                               "
         "    return [n / 2];              "
         " };                              "
         "                                 "
         " var a := ceil(sqrt(n));         "
         "                                 "
         " while (not(is_square(a^2 - n))) "
         " {                               "
         "    a += 1;                      "
         " };                              "
         "                                 "
         " var b := sqrt(a^2 - n);         "
         "                                 "
         " a - b;                          "
      ));

   const std::string factorize_composites_program =
      " for (var i := 0; i < composites[]; i += 1)                               "
      " {                                                                        "
      "    var n       := composites[i];                                         "
      "    var factor0 := fermat(n);                                             "
      "    var factor1 := n / factor0;                                           "
      "                                                                          "
      "    if ((factor0 * factor1 == n) and (factor0 != 1))                      "
      "    {                                                                     "
      "       println('n: ', n, ' factors: { ', factor0 ,' , ', factor1 ,' } '); "
      "    }                                                                     "
      "    else                                                                  "
      "    {                                                                     "
      "       println('failed to factorize ', n);                                "
      "    }                                                                     "
      " }                                                                        "
      "                                                                          ";
   expression_t expression;
   expression.register_symbol_table(symbol_table);

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

   expression.value();
}

// Assembly:
subq $0x1918, %rsp           # imm = 0x1918
leaq 0x34d052(%rip), %rsi    # 0x468890
leaq 0x1830(%rsp), %rdi
movl $0xe0, %edx
callq 0x114090
leaq 0x17a7(%rsp), %rdi
movq %rdi, 0x78(%rsp)
callq 0x114660
movq 0x78(%rsp), %rdx
leaq 0x347cf7(%rip), %rsi    # 0x463565
leaq 0x17a8(%rsp), %rdi
callq 0x11b770
jmp 0x11b87d
leaq 0x17c8(%rsp), %rdi
leaq 0x17a8(%rsp), %rsi
callq 0x11c3f0
jmp 0x11b894
leaq 0x17a8(%rsp), %rdi
callq 0x1147a8
leaq 0x17a7(%rsp), %rdi
callq 0x114790
leaq 0x1788(%rsp), %rdi
movl $0x1, %esi
callq 0x11c500
jmp 0x11b8c2
leaq 0x1767(%rsp), %rdi
movq %rdi, 0x70(%rsp)
callq 0x114660
movq 0x70(%rsp), %rdx
leaq 0x347c8c(%rip), %rsi    # 0x46356c
leaq 0x1768(%rsp), %rdi
callq 0x11b770
jmp 0x11b8ef
leaq 0x1788(%rsp), %rdi
leaq 0x1768(%rsp), %rsi
leaq 0x1830(%rsp), %rdx
callq 0x11c540
jmp 0x11b90e
leaq 0x1768(%rsp), %rdi
callq 0x1147a8
leaq 0x1767(%rsp), %rdi
callq 0x114790
leaq 0x173f(%rsp), %rdi
movq %rdi, 0x68(%rsp)
callq 0x114660
movq 0x68(%rsp), %rdx
leaq 0x347c31(%rip), %rsi    # 0x463577
leaq 0x1740(%rsp), %rdi
callq 0x11b770
jmp 0x11b955
leaq 0x1788(%rsp), %rdi
leaq 0x1740(%rsp), %rsi
leaq 0x17c8(%rsp), %rdx
callq 0x11c5e0
jmp 0x11b974
leaq 0x1740(%rsp), %rdi
callq 0x1147a8
leaq 0x173f(%rsp), %rdi
callq 0x114790
leaq 0xd50(%rsp), %rdi
leaq 0x1788(%rsp), %rsi
callq 0x11c7e0
jmp 0x11b9a5
leaq 0xcc0(%rsp), %rdi
callq 0x11c9d0
jmp 0x11b9b4
leaq 0xc9f(%rsp), %rdi
movq %rdi, 0x60(%rsp)
callq 0x114660
movq 0x60(%rsp), %rdx
leaq 0x347bad(%rip), %rsi    # 0x46357f
leaq 0xca0(%rsp), %rdi
callq 0x11b770
jmp 0x11b9e1
leaq 0xcc0(%rsp), %rdi
leaq 0xca0(%rsp), %rsi
callq 0x11ca40
movq %rax, 0x58(%rsp)
jmp 0x11b9fd
leaq 0xc77(%rsp), %rdi
movq %rdi, 0x50(%rsp)
callq 0x114660
movq 0x50(%rsp), %rdx
leaq 0x347aa2(%rip), %rsi    # 0x4634bd
leaq 0xc78(%rsp), %rdi
callq 0x11b770
jmp 0x11ba2a
movq 0x58(%rsp), %rdi
leaq 0xc78(%rsp), %rsi
callq 0x11ca70
movq %rax, 0x48(%rsp)
jmp 0x11ba43
leaq 0xc4f(%rsp), %rdi
movq %rdi, 0x40(%rsp)
callq 0x114660
movq 0x40(%rsp), %rdx
leaq 0x347b28(%rip), %rsi    # 0x463589
leaq 0xc50(%rsp), %rdi
callq 0x11b770
jmp 0x11ba70
movq 0x48(%rsp), %rdi
leaq 0xc50(%rsp), %rsi
callq 0x11caa0
movq %rax, 0x38(%rsp)
jmp 0x11ba89
movq 0x38(%rsp), %rsi
leaq 0xd50(%rsp), %rdi
xorl %edx, %edx
callq 0x11c980
jmp 0x11ba9f
leaq 0xc50(%rsp), %rdi
callq 0x1147a8
leaq 0xc4f(%rsp), %rdi
callq 0x114790
leaq 0xc78(%rsp), %rdi
callq 0x1147a8
leaq 0xc77(%rsp), %rdi
callq 0x114790
leaq 0xca0(%rsp), %rdi
callq 0x1147a8
leaq 0xc9f(%rsp), %rdi
callq 0x114790
leaq 0xcc0(%rsp), %rdi
callq 0x11cad0
leaq 0xbb8(%rsp), %rdi
callq 0x11c9d0
jmp 0x11bb09
leaq 0xb97(%rsp), %rdi
movq %rdi, 0x30(%rsp)
callq 0x114660
movq 0x30(%rsp), %rdx
leaq 0x347a9f(%rip), %rsi    # 0x4635c6
leaq 0xb98(%rsp), %rdi
callq 0x11b770
jmp 0x11bb36
leaq 0xbb8(%rsp), %rdi
leaq 0xb98(%rsp), %rsi
callq 0x11ca40
movq %rax, 0x28(%rsp)
jmp 0x11bb52
leaq 0xb6f(%rsp), %rdi
movq %rdi, 0x20(%rsp)
callq 0x114660
movq 0x20(%rsp), %rdx
leaq 0x3478c0(%rip), %rsi    # 0x463430
leaq 0xb70(%rsp), %rdi
callq 0x11b770
jmp 0x11bb7f
movq 0x28(%rsp), %rdi
leaq 0xb70(%rsp), %rsi
callq 0x11ca70
movq %rax, 0x18(%rsp)
jmp 0x11bb98
leaq 0xb47(%rsp), %rdi
movq %rdi, 0x10(%rsp)
callq 0x114660
movq 0x10(%rsp), %rdx
leaq 0x347a17(%rip), %rsi    # 0x4635cd
leaq 0xb48(%rsp), %rdi
callq 0x11b770
jmp 0x11bbc5
movq 0x18(%rsp), %rdi
leaq 0xb48(%rsp), %rsi
callq 0x11caa0
movq %rax, 0x8(%rsp)
jmp 0x11bbde
movq 0x8(%rsp), %rsi
leaq 0xd50(%rsp), %rdi
xorl %edx, %edx
callq 0x11c980
jmp 0x11bbf4
leaq 0xb48(%rsp), %rdi
callq 0x1147a8
leaq 0xb47(%rsp), %rdi
callq 0x114790
leaq 0xb70(%rsp), %rdi
callq 0x1147a8
leaq 0xb6f(%rsp), %rdi
callq 0x114790
leaq 0xb98(%rsp), %rdi
callq 0x1147a8
leaq 0xb97(%rsp), %rdi
callq 0x114790
leaq 0xbb8(%rsp), %rdi
callq 0x11cad0
leaq 0xb1f(%rsp), %rdi
movq %rdi, (%rsp)
callq 0x114660
movq (%rsp), %rdx
leaq 0x347bd6(%rip), %rsi    # 0x463841
leaq 0xb20(%rsp), %rdi
callq 0x11b770
jmp 0x11bc7a
leaq 0xb1f(%rsp), %rdi
callq 0x114790
leaq 0xaf8(%rsp), %rdi
callq 0x11cb10
jmp 0x11bc96
leaq 0xaf8(%rsp), %rdi
leaq 0x1788(%rsp), %rsi
callq 0x11cbc0
jmp 0x11bcad
leaq 0x80(%rsp), %rdi
movl $0x7f, %esi
callq 0x11cc70
jmp 0x11bcc1
leaq 0x1d0(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0x11cda0
jmp 0x11bcd8
leaq 0x80(%rsp), %rdi
callq 0x11d5d0
leaq 0x1d0(%rsp), %rdi
leaq 0xb20(%rsp), %rsi
leaq 0xaf8(%rsp), %rdx
callq 0x11d640
jmp 0x11bd04
leaq 0xaf8(%rsp), %rdi
callq 0x11ded0
jmp 0x11bd13
leaq 0x1d0(%rsp), %rdi
callq 0x11def0
leaq 0xaf8(%rsp), %rdi
callq 0x11e0f0
leaq 0xb20(%rsp), %rdi
callq 0x1147a8
leaq 0xd50(%rsp), %rdi
callq 0x11e130
leaq 0x1788(%rsp), %rdi
callq 0x11e1c0
leaq 0x17c8(%rsp), %rdi
callq 0x11e240
addq $0x1918, %rsp           # imm = 0x1918
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11bda0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
leaq 0x17a8(%rsp), %rdi
callq 0x1147a8
leaq 0x17a7(%rsp), %rdi
callq 0x114790
jmp 0x11c136
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11c129
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11be02
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
leaq 0x1768(%rsp), %rdi
callq 0x1147a8
leaq 0x1767(%rsp), %rdi
callq 0x114790
jmp 0x11c11c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11be4b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
leaq 0x1740(%rsp), %rdi
callq 0x1147a8
leaq 0x173f(%rsp), %rdi
callq 0x114790
jmp 0x11c11c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11c11c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11c10f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11bf58
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11bf4b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11bf3e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11bf31
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11bf24
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
leaq 0xc50(%rsp), %rdi
callq 0x1147a8
leaq 0xc4f(%rsp), %rdi
callq 0x114790
leaq 0xc78(%rsp), %rdi
callq 0x1147a8
leaq 0xc77(%rsp), %rdi
callq 0x114790
leaq 0xca0(%rsp), %rdi
callq 0x1147a8
leaq 0xc9f(%rsp), %rdi
callq 0x114790
leaq 0xcc0(%rsp), %rdi
callq 0x11cad0
jmp 0x11c10f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11c040
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11c033
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11c026
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11c019
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11c00c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
leaq 0xb48(%rsp), %rdi
callq 0x1147a8
leaq 0xb47(%rsp), %rdi
callq 0x114790
leaq 0xb70(%rsp), %rdi
callq 0x1147a8
leaq 0xb6f(%rsp), %rdi
callq 0x114790
leaq 0xb98(%rsp), %rdi
callq 0x1147a8
leaq 0xb97(%rsp), %rdi
callq 0x114790
leaq 0xbb8(%rsp), %rdi
callq 0x11cad0
jmp 0x11c10f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
leaq 0xb1f(%rsp), %rdi
callq 0x114790
jmp 0x11c10f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11c102
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
jmp 0x11c0f5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
leaq 0x80(%rsp), %rdi
callq 0x11d5d0
jmp 0x11c0f5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1798(%rsp)
movl %eax, 0x1794(%rsp)
leaq 0x1d0(%rsp), %rdi
callq 0x11def0
leaq 0xaf8(%rsp), %rdi
callq 0x11e0f0
leaq 0xb20(%rsp), %rdi
callq 0x1147a8
leaq 0xd50(%rsp), %rdi
callq 0x11e130
leaq 0x1788(%rsp), %rdi
callq 0x11e1c0
leaq 0x17c8(%rsp), %rdi
callq 0x11e240
movq 0x1798(%rsp), %rdi
callq 0x114450
nopw %cs:(%rax,%rax)
nopl (%rax)