Rational ^ Rational

Why does this make a Float64 instead of a Rational?

julia> ((2//1)^(-4//1))

Is this the only way to get a Rational out of exponentiation?

julia> Rational((2//1)^(-4//1))
1 Like

This is the method being called:

^(x::Number, y::Rational) = x^(y.num/y.den)

I suppose the thinking is that you probably don’t want this:

a = 2 // 1
b = -3 // 8

julia> Rational(a ^ b)

Rational to the power of rational is typically irrational:

julia> (2//1)^(1//2)

An important principle in Julia to ensure performance, is type stability. I.e. the type of a function’s return value should be a function of the input types. The return type should not vary with the input values, only with their types. Some powers with rational numbers will yield a rational result, but most often it does not. To ensure type stability the Rational{Int64} ^ Rational{Int64} operation returns a Float64. It’s a design choice (it could have been BigFloat or Float32 or whatever, but it is Float64).

1 Like

And note that Rational ^ Integer is a Rational.

julia> ((2//1)^(-4))

Depending on types you get Float46 (reasonable) or BigFloat (also reasonable), and you can do (but it’s not reasonable):

julia> Rational(big(1//2)^big(1//2))  # scroll to right to see this is still a "Rational", type that is

Rational there implies you get a rational out, but that’s wrong, as the calculated value an irrational number (so I would avoid typing that in code), you only get the most accurate (considering default precision of BigFloat) rational of the resulting BigFloat number, which was already an approximation.

Since you know the result in in general, for a^b, irrational, i.e. none of the approximations are accurate, then this is more reasonable, if you only want some rational approximation:

julia> rationalize(big(1//2)^big(1//2))

Yes, the type you get is still a Rational, but look at the help string for rationalize, then it’s clear it’s an approximation. I would still just keep the Float64 (or even convert BigFloat to Float64 too).

Or maybe even:

julia> rationalize(Int16, big(1//2)^big(1//2))  # possibly rather Rational{Int64}(rationalize(Int16, big(1//2)^big(1//2)))
1 Like