Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with large factorial #464

Open
wjamesjr opened this issue Jan 5, 2024 · 11 comments
Open

Issue with large factorial #464

wjamesjr opened this issue Jan 5, 2024 · 11 comments

Comments

@wjamesjr
Copy link

wjamesjr commented Jan 5, 2024

I know that I am doing something wrong but just can't figure what. The largest factorial that I can get converted to a mpfr is 44787927. Above this number I get inf as a result. I am on gmpy2 2.15 and python 3.11.7 on an Apple silicon Mac M3.

if name == "main":
n = 44787927
gmpy2.get_context().emin = gmpy2.get_emin_min()
gmpy2.get_context().emax = gmpy2.get_emax_max()
print("emin", gmpy2.get_context().emin)
print("emax", gmpy2.get_context().emax)
print("max precision", gmpy2.get_max_precision())
gmpy2.get_context().precision = 100
print("precision set to", gmpy2.get_context().precision)
factn = gmpy2.factorial(n)
print(factn)
n = 44787928
factn = gmpy2.factorial(n)
print(factn)
exit(0)

I get the following result running the above code.

emin -4611686018427387903
emax 4611686018427387903
max precision 9223372036854775551
precision set to 100
1.9481086289383819889097566536014e+323228493
inf

@casevh
Copy link
Collaborator

casevh commented Jan 5, 2024

gmpy2.gamma() has a similar behavior. I vaguely recollect another report of this issue and it was a limitation of the MPFR library. I haven't found the details but I'll keep looking.

@casevh
Copy link
Collaborator

casevh commented Jan 5, 2024

I found this comment in MPFR's gamma.c:

 if (u < 44787929UL && bits_fac (u - 1) <= p + (rnd_mode == MPFR_RNDN))
    /* bits_fac: lower bound on the number of bits of m,
       where gamma(x) = (u-1)! = m*2^e with m odd. */
    return mpfr_fac_ui (gamma, u - 1, rnd_mode);
  /* if bits_fac(...) > p (resp. p+1 for rounding to nearest),
     then gamma(x) cannot be exact in precision p (resp. p+1).
     FIXME: remove the test u < 44787929UL after changing bits_fac
     to return a mpz_t or mpfr_t. */

@wjamesjr
Copy link
Author

wjamesjr commented Jan 5, 2024

Yep, that looks like the issue. Strange number to set as a cutoff! I will fall back to a python factorial algorithm with some bit slicing. Thanks for the quick response!

@wjamesjr
Copy link
Author

wjamesjr commented Jan 5, 2024

Looks like the issue runs deeper than just gamma(). The below code computing a mpz factorial fails as well, with result inf. 44787927 still works. Is there some trick to converting very large mpz values to mpfr??

n = 44787928
gmpy2.get_context().emin = gmpy2.get_emin_min()
gmpy2.get_context().emax = gmpy2.get_emax_max()
print("emin", gmpy2.get_context().emin)
print("emax", gmpy2.get_context().emax)
print("max precision", gmpy2.get_max_precision())
gmpy2.get_context().precision = 100
print("precision set to", gmpy2.get_context().precision)
factn = gmpy2.fac(n)
print(factn.num_digits())
factn2 = mpfr(factn)
print(factn2)
exit(0)

@wjamesjr
Copy link
Author

wjamesjr commented Jan 5, 2024

Looks like I have a hard limit on size of mpz that will convert to mpfr. The below code works. Change 2 ** 29 to 2 ** 30 and it goes to inf again. Should mpfr be limited in bit size?? I thought that's what precision provided.

gmpy2.get_context().emin = gmpy2.get_emin_min()
gmpy2.get_context().emax = gmpy2.get_emax_max()
print("emin", gmpy2.get_context().emin)
print("emax", gmpy2.get_context().emax)
print("max precision", gmpy2.get_max_precision())
gmpy2.get_context().precision = 100
print("precision set to", gmpy2.get_context().precision)
t1 = mpz(1) << (2 ** 29)
t2 = mpfr(t1)
print(t2)

@casevh
Copy link
Collaborator

casevh commented Jan 5, 2024 via email

@wjamesjr
Copy link
Author

Reported a bug to the MPFR development team. After some discussion they have decided to investigate. They say that they do not test for large bit precisions due to the amount of time required. But in this case they have decided to look into it to find if it is some int32 overflow or something like large multiplication issues and such.

@skirpichev
Copy link
Contributor

Could we kept here a link to MPFR issue or maillist thread?

@wjamesjr
Copy link
Author

https://sympa.inria.fr/sympa/arc/mpfr/2024-10/msg00002.html

Above is mail list thread hyperlink where I reported the bug.

@casevh
Copy link
Collaborator

casevh commented Oct 12, 2024 via email

@wjamesjr
Copy link
Author

The sample code that I gave to the MPFR development team had an issue. The c++ mpfr wrapper was using an int vs long argument for a call to convert digits to bits for precision. After changing that argument to a long and increasing emax and emin values the code worked. Which means that MPFR will work for bit precisions over 2 ** 30, at least for the code I was testing. Now, I still can't get gmpy to work for the same algorithm for above the 2 ** 30 bit precision threshold. I will submit test code as a separate issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants