I have a partially working version of the root functions based on Newton’s method somewhat working:
?- M is (2^32+3), N is M^3, nth_integer_root_and_remainder(3, N, Root, Remainder).
M = Root, Root = 4294967299,
N = 79228162680285034372894031899,
Remainder = 0.
but there’s an issue when I try to find the same root in an arithmetic expression:
?- M is (2^32+3), N is M^3,R is N**1r3.
It either produces the wrong result or hangs requiring a manual abort. Including some print statements for debugging, the code looks like:
mpz_rootrem
void
mpz_rootrem(mpz_t rop, mpz_t rem, const mpz_t op, unsigned long int n)
{
mpz_t cn,cn1,nxt,x;
mpz_init_set_ui(cn, n); // const n
mpz_init_set_ui(cn1, n-1); // const n-1
mpz_init_set(nxt, op);
mpz_init(x);
printf("n= %i ",n); bf_print_str("op ",op);
do // using rop and rem as temporaries
{ mpz_set(x, nxt); // x = nxt
bf_print_str("op before pow ",op);
// mpz_pow_ui(rop, x, n-1); // rop = pow(x, n-1) PLUS 1
bf_pow(rop, x, cn1, BF_PREC_INF, BF_RNDN); // rop = pow(x, n-1)
bf_print_str("op after pow ",op);
mpz_fdiv_qr(rop, rem, op, rop); // rop = op // rop
// mpz_addmul_ui(rop, &s, n-1); // rop = rop + x * (n-1) PLUS 1
mpz_mul_ui(rem, x, n-1); // rem = x * (n-1)
mpz_add(rop, rop, rem); // rop = rop + rem
mpz_fdiv_qr(nxt, rem, rop, cn); // nxt = rop // n
} while (mpz_cmp(nxt, x) < 0);
mpz_set(rop, x);
bf_pow(rem, rop, cn, BF_PREC_INF, BF_RNDN); // rem = pow(rop, n)
bf_sub(rem, op, rem, BF_PREC_INF, BF_RNDN); // rem = op - rem
mpz_clear(cn);
mpz_clear(cn1);
mpz_clear(nxt);
mpz_clear(x);
return;
}
When I look at the debug output from the working query:
?- M is (2^32+3),N is M^3, nth_integer_root_and_remainder(3, N, Root, Remainder).
n= 3 op =0x0.800000048000000d8000000d80000000p97
op before pow =0x0.800000048000000d8000000d80000000p97
op after pow =0x0.800000048000000d8000000d80000000p97
op before pow =0x0.800000048000000d8000000d80000000p97
op after pow =0x0.800000048000000d8000000d80000000p97
op before pow =0x0.800000048000000d8000000d80000000p97
op after pow =0x0.800000048000000d8000000d80000000p97
.
.
This is good, i.e., no change to op
value. But the failing query outputs:
?- M is (2^32+3),N is M^3,R is N**1r3.
n= 3 op =0x0.800000048000000d8000000d80000000p97
op before pow =0x0.800000048000000d8000000d80000000p97
op after pow =0x0.80000009000000438000010e0000025f800002d90000016c8000000000000000p193
op before pow =0x0.800000048000000d8000000dc0000000p98
op after pow =0x0.e38e38f38e38e40638e39019c71c76071c71cc4471c71f12p191
op before pow =0x0.aaaaaab0aaaaaabcaaaaaabd80000000p97
op after pow =0x0.ca4587f4f03291cca45880181948b4ce9e0656e1948b1244p190
op before pow =0x0.e38e38eb8e38e3a638e38e5300000000p96
op after pow =0x0.b3cc07129c9eba7d03dce3a3a4b267d41ab04d3a4b264920p189
^C^C
WARNING: By typing Control-C twice, you have forced an asynchronous
WARNING: interrupt. Your only SAFE operations are: c(ontinue), p(id),
WARNING: s(stack) and e(xit). Notably a(abort) often works, but
WARNING: leaves the system in an UNSTABLE state
This indicates the bf_pow
function is somehow modifying the op
value, which isn’t even an argument to the function, suggesting memory corruption of some kind. And using the mpz_pow_ui
function (which calls bf_pow
) doesn’t change anything. Also note the op
value is modified further before the start of the next iteration.
I don’t have the expertise/tools to tackle this, but any suggestions for resolving this welcome.