Should there be a native angle type?

Between dealing with degrees versus radians, their specialized functions (e.g. `cosd` versus `cos`), optimizing their representation (wrapping around, defining counter- and clockwise, etc), and using `Unitful.jl`, I started thinking, should `Julia` have a native `Angle` type…? Will the overhead not be worth the gain?

1 Like

It’s not an overhead issue - the question is “what should be in Base” vs “what should be in packages”.

On one hand Unitful seems like the perfect place for these units. On the other hand, Base defines (and therefore “owns”) trigonometry functions like `sin` and `sind` and therefore obviously has a pretty good idea of what radians and degrees are, and interface improvements are always welcome. It might be possible something simple and subtle would be accepted, but having all possible windings and sense of directions… this seems less likely to me.

2 Likes

I have a feeling that forcing everyone to predefine quantities that go into a `sin` function as `Degree` or `Radian` (both subtypes of `Angle`) wouldn’t be very popular. But it does make some sense… On the other hand, what should `acos` return, `Degree` or `Radian`…? hmm…

Just out of curiosity, in what context would you want `acos(x)` to return degrees?

Degrees are convenient because people find small, conveniently factorizable integers easy to work with — eg 60° is more intuitive to most non-mathematicians than π/3. But when you use an arbitrary argument to `acos`, you will get some float anyway, and getting that in degrees instead of radians may not be that large of an advantage.

1 Like

Over at the libcairo mailing list there is currently a medium sized discussion to add API to deal with angles in deg because angles in deg (esp. 30/45/90 multiples) have more ‘meaning’ and lead to exact transformation matrices. It’s really a matter of perspective and personal preferences.
(read as: you get numerical problems, as irrational numbers like pi/3 cannot be represented in float)

The issue you mention is well understood, and Julia has dealt with it already (eg `Base.cospi`). The question was about `acos`. I am not arguing that a version that gives degrees is not useful, merely asking for examples in actual code; I think they would focus the discussion.

1 Like

The usefulness of `acos` returning degrees is not different from any other situation where angles are expressed in terms of degrees instead of radians. They are easier for biologists (in my case).

Normally you’d never touch degrees and therefore never worry about which is it, but if the interface with the user includes the possibility of degrees, then this becomes a concern (which one can solve locally). It would be nice to not worry about it. Theoretically, the type of angle `acos` would return could be assigned randomly and things would still just work…

A wild thought, with a Angle type, we could have specialized angles that are multiples of pi (or 180, depending on the type), and therefore would elicit the cospi automatically. cool…

Base.cospi is not really a matching example, as:

Compute cos(πx) more accurately than cos(pi*x), especially for large x.

and 1/3 still isn’t represented in float.

Indeed. Try

``````cospi(1//3)
``````

It occurs to me that there are a bunch of cases where julia’s type system could be used to introduce cool functionalities when it comes to these entities that traditionally are not considered “worth” typing. Angle is the subject of this thread, but Sign is another. Examples of such entities that I think are not typed (or less so) in other languages are Time, Diagonal, Irrational, etc. It’s not entirely clear to me why these get their own (native) type and, say, Angle doesn’t.

It seems like there’s a huge potential to refactor trig functions. Here’s a list of sin family functions in base exports; there’s a similar family for every trig function.

``````asin,
asind,
asinh,
sin,
sinc,
sind,
sinh,
sinpi
``````

It seems like this would better be handled with dispatch and/or keyword arguments? Just keyword arguments like `hyperbolic = true`, `degrees = true`, and `inverse = true` would go a long way.

2 Likes

A combination of angle types (`AngleInDegrees`, `AngleInRadians`, `AngleInPis`) and keywords (`hyperbolic`, `cardinal`, `inverse`, `cofunction` and `reciprocal`) could in fact get you down to exactly two trig functions (`sin` and `tan`). Of course this is a bit extreme, but so is the amount of trig exports in base.

1 Like

Branching on arguments is too slow. Trig functions are expected to run as fast as possible.

Also, the names are standard across almost every language that has these functions, so changing them would confuse a lot of users.

3 Likes

There shouldn’t be a problem with adding a few methods for an Angle type. So people will always be able to run `sin` on a float, but they could also run `sin` on a `Degree <: Angle`, and `sin` will behave like `sind`.

1 Like

And not just programming languages. These names mostly correspond to the names used in mathematics. They are different functions, and should have different names.

Agreed, but `sind` versus `sin` isn’t a “real” mathematical distinction (or is it?). On the other hand, that’s something an Angle type might take care of.

Yes, sin and sind is a different story.

@yakir12, there are two issues here:

1. would a separate `Angle` type be useful?
2. should this be part of `Base`?

A priori arguments can only get you so far; the best way to demonstrate 1. is to write a package and see if it gets used. This should also help you refine the interface.

I guess 2. will only be relevant if the package is widely used, and you demonstrate that inclusion in `Base` could achieve something that a package could not. That’s a tall order, but even if you think so, it comes after the package.

4 Likes

Unitful does the correct thing already with respect to `sin` vs `sind`:

``````julia> using Unitful.°

julia> sin(720π/180)
-4.898587196589413e-16

julia> sin(720°)
0.0

julia> sind(720)
0.0
``````
5 Likes