Hi there, I’ve been using the Julia REPL a lot as a calculator for my day to day life (as a student of engineering, this is really helpful, and definitely much more comfortable to use than a Casio calc for simple things, or using some other REPL like Python’s).
But I’ve found something that I’d like to know a workaround for.
For example, if I type something like arccos(-0.5) on my Casio (in RAD), I’d get (2/3)pi as a result.
However, in Julia, I get the approximate rational result for that as I enter acos(-0.5) on the REPL (I get 2.0943951023931957 which is a very great approximation of the result, but not exact).
I wonder, is there a way to get the outcome as a multiple of pi for these cases, or maybe a function that does this afterwards that I can pipe to this result?
Of course I could just divide the result by pi and do that by hand but this is not something I’m willing to do
So, I know pi/2 is no existing type in Julia (or so I believe), neither is pi//2 because pi is obviously irrational, so perhaps just having the fractional part and knowing that it is * pi would do.
So like (imagining an acospi function)
acospi(cos(pi/3))
1//3 (times pi)
Your solution is pretty good, but perhaps a bit long to type (though it works well as a ‘quick fix’ for my problem), thanks for that!
These are impossible in general. Out of the very few special cases you give the intermediate result already cannot be exactly represented. If for whatever reason you really need fraction representation of angle, you should use symbolic calculation instead and you will not be able to find anything like that in the base math functions.
julia> struct PiF
x
end
julia> function Base.show(io :: IO, x :: PiF)
y = rationalize(x.x/π)
println("($(y.num)/$(y.den))π")
end
julia> PiF(acos(cos(pi/2)))
(1/2)π
julia> PiF(asin(sin(π/6)))
(1/6)π
But I am not sure how useful is that. It is pretty though
Or even simpler, just define the function:
julia> function pifrac(x)
y = rationalize(x/π)
println("($(y.num)/$(y.den))π")
end
pifrac (generic function with 1 method)
julia> pifrac(asin(sin(π/6)))
(1/6)π
Note that these are just introducing more errors to the calculation in general. Unless your actual goal is to do approximate calculation that somehow want to use fractions as much as possible or you somehow know that all the numbers you’ll ever deal with are fractions with smal denominators you should not use any of these.
This reminds me an old university joke.
A businessman hires a mathematician, a computer scientist and a physicist in order to be able to win all the trifecta horse race bets.
The mathematician after long weeks of lemmas, theorems and conjectures, concludes that the problem is formally irresolvable. Then, the computer scientist takes up the challenge on a supercomputer and after having written quantities of algorithms he happily announces that it will take just a few hundred years to calculate the result of each trifecta. The physicist, with a smile on his face, informs his eminent colleagues that he has the solution. He approaches a blackboard and while drawing a curve he begins by saying: “Let us approximate the horse by a perfect sphere…”
julia> struct PiF
x
end
julia> function Base.show(io::IO, x::PiF)
y = rationalize(x.x/π)
print("($(y.num)/$(y.den))π")
end
julia> function Base.print(stdout::IO,x::AbstractVector{PiF})
print("[")
for i in firstindex(x):lastindex(x)-1
print("$(x[i]), ")
end
print(" $(x[end])]")
end
julia> println(v)
[(2/3)π, (1/3)π, (1/4)π ]
julia> print(v)
[(2/3)π, (1/3)π, (1/4)π ]
And better still, it actually uses exact calculation, not approximate calculation using rationalize, so it will always give the correct result.
(Internally it works via representation using minimal polynomials)