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

Rational power of BigFloat should use specialised MPFR function #55204

Open
dpsanders opened this issue Jul 21, 2024 · 9 comments
Open

Rational power of BigFloat should use specialised MPFR function #55204

dpsanders opened this issue Jul 21, 2024 · 9 comments
Labels
bignums BigInt and BigFloat maths Mathematical functions rationals The Rational type and values thereof

Comments

@dpsanders
Copy link
Contributor

big(1.3)^(1//7) currently converts the rational to BigFloat before computing the power, thereby losing accuracy.

It should instead use the specialised MPFR function mpfr_rootn_si.

cc @oscardssmith

@giordano giordano added rationals The Rational type and values thereof bignums BigInt and BigFloat labels Jul 21, 2024
@dpsanders
Copy link
Contributor Author

Apparently the code is still in the library

@dpsanders
Copy link
Contributor Author

julia> x = interval(8.673020346900622e8, 8.673020346900623e8)

julia> IntervalArithmetic._rootn_round(sup(x), 8, RoundUp)
13.100000000000001

@dpsanders
Copy link
Contributor Author

At some point we had an nthroot function. This should maybe be renamed rootn and reinstated?

@dpsanders
Copy link
Contributor Author

(The rootn function is required recommended by the 1788 standard in section 10.6.)

@dpsanders
Copy link
Contributor Author

My bad, I see we have the rootn function already... In that case we should just make rational power use that function!

@dpsanders
Copy link
Contributor Author

That works if the numerator == 1, so the rational is 1 // n.
If the rational is x ^ (p // q) then we could do nthroot(x, q)^p. This will not be guaranteed to be correctly rounded.

@oscardssmith
Copy link
Member

oscardssmith commented Jul 22, 2024

Note that nthroot(x, q) is going to lose a lot of accuracy for x close to 0.

@nsajko nsajko added the maths Mathematical functions label Jul 25, 2024
@ararslan
Copy link
Member

Would something like this be a good first-pass solution?

diff --git a/base/mpfr.jl b/base/mpfr.jl
index ed3ea5937c..7833b65284 100644
--- a/base/mpfr.jl
+++ b/base/mpfr.jl
@@ -733,6 +733,25 @@ function ^(x::BigFloat, y::BigInt)
     return z
 end

+_rootn(z, x, n::ClongMax)  = ccall((:mpfr_rootn_si, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Clong,  MPFRRoundingMode), z, x, n, rounding_raw(BigFloat))
+_rootn(z, x, n::CulongMax) = ccall((:mpfr_rootn_ui, libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, MPFRRoundingMode), z, x, n, rounding_raw(BigFloat))
+
+function ^(x::BigFloat, y::Rational{<:Union{ClongMax,CulongMax}})
+    # If `y` is of the form `±1//n`, we can use MPFR's builtin nth root without needing to
+    # convert the `Rational` to a `BigFloat`. The `copysign` is because `mpfr_rootn_*` takes
+    # a negative power to mean `-1//n` but `Rational{<:Signed}` uses the numerator to track
+    # the sign.
+    if isone(abs(numerator(y)))
+        z = BigFloat()
+        _rootn(z, x, copysign(denominator(y), numerator(y)))
+        return z
+    else
+        # TODO: Determine whether there are cases where we should prefer doing something
+        # like `x^(p//q) = rootn(x, q)^p`, which will have accuracy issues for `x` near 0
+        return x^BigFloat(y)
+    end
+end
+
 ^(x::BigFloat, y::Integer)  = typemin(Clong)  <= y <= typemax(Clong)  ? x^Clong(y)  : x^BigInt(y)
 ^(x::BigFloat, y::Unsigned) = typemin(Culong) <= y <= typemax(Culong) ? x^Culong(y) : x^BigInt(y)

@oscardssmith
Copy link
Member

Actually thinking about this more, as long as x^p is neither 0 or inf, nthroot(x^p, q) will be pretty accurate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bignums BigInt and BigFloat maths Mathematical functions rationals The Rational type and values thereof
Projects
None yet
Development

No branches or pull requests

5 participants