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