Skip to content

arb_pow gives NaN for an exact integer exponent when the midpoint of x is zero #2908

Closed

Description

@yidiq7

Describe the bug
arb_pow(z, x, y, prec) gives NaN when y is an exact small integer and the midpoint of x is exactly zero with a nonzero radius. A ball with the midpoint 1e-30 and the same radius gives a finite and correct result. So the result depends on the midpoint, not on the set of numbers that the ball holds.

The cause is the condition of the integer and half-integer path in src/arb/pow.c (line 64 on main):

if (arb_is_exact(y) && !arf_is_special(arb_midref(x)))

arf_is_special is also true for a zero midpoint. So the ball [0 +/- r] does not get to arb_pow_fmpz_binexp, and it goes to the general case exp(y log x). The log of a ball that holds negative numbers is NaN. I think that the test is there to keep infinite and NaN midpoints out of the fast path.

Steps to reproduce
In python-flint, x ** arb(2) calls arb_pow with the exact exponent 2:

import flint
from flint import arb, acb

print("python-flint", flint.__version__, "FLINT", flint.__FLINT_VERSION__)
for m in (0, 1e-30, 0.05, -0.05):
    x = arb(m, 0.1)
    print(f"mid {m:g}: x ** arb(2) = {x ** arb(2)}, x * x = {x * x}")
print(f"acb: acb(arb(0, 0.1)) ** 2 = {acb(arb(0, 0.1)) ** 2}")

Output:

python-flint 0.9.0 FLINT 3.6.0
mid 0: x ** arb(2) = nan, x * x = [+/- 0.0101]
mid 1e-30: x ** arb(2) = [+/- 0.0101], x * x = [+/- 0.0101]
mid 0.05: x ** arb(2) = [+/- 0.0226], x * x = [+/- 0.0226]
mid -0.05: x ** arb(2) = [+/- 0.0226], x * x = [+/- 0.0226]
acb: acb(arb(0, 0.1)) ** 2 = [+/- 0.0101]

All four balls hold zero and negative numbers. Only the ball with the midpoint 0 gives NaN.

Expected behavior
arb_pow with an exact integer exponent gives a finite enclosure of x^n for each finite ball x, as arb_pow_fmpz does. For x = [0 +/- 0.1] and n = 2, the result must hold [0, 0.01], for example [+/- 0.0101] as x * x gives. NaN is a valid enclosure, but it holds no information, and the same exponent gives a finite ball for a midpoint of 1e-30 or for acb_pow.

A possible fix: let a zero midpoint with a finite radius take the integer path. arb_pow_fmpz already gives a finite ball for arb(0, 1) (flintlib/python-flint#427 uses it).

System (please complete the following information):

  • System CPU: Intel(R) Xeon(R) Platinum 8480CL (x86_64), Linux 4.18.0 (RHEL 8), glibc 2.28
  • Version of FLINT (if using Git, please specify commit): 3.6.0, the copy in the python-flint 0.9.0 wheel from PyPI (cp310-abi3-manylinux_2_17_x86_64), with Python 3.12.14. The condition above is the same on main.
  • How FLINT was configured (i.e. options pushed): the prebuilt python-flint wheel
  • Output of configure
    Not available: FLINT came prebuilt in the python-flint 0.9.0 wheel.
    

Additional context
flintlib/python-flint#426 reports the same NaN for arb(0, 1) ** 2. Its fix, flintlib/python-flint#427, makes arb.__pow__ call arb_pow_fmpz for int and fmpz exponents. Other exponent types, for example arb(2), still go to arb_pow, and C code that calls arb_pow gets the NaN too.

Activity

  1. added a commit that references this issue on Oct 27, 2026
    f2038a4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions