Join the discussion

Write your take first — we'll ask for email only when you're ready to publish.

  • Hacker News
  • This seems to be mostly from the perspective of what makes the most sense to use at an API boundary.

    Rather than trying to agree on the best meaning the various integers or floats that we're passing around, maybe we should instead build a more complex angle type that doesn't force callers to conform. Like, I can pass minutes or seconds to functions that accept a time type and it just works because they're not being collapsed to numbers. Is there any reason we couldn't do that with angles too?

  • “The math is easy!” …proceeds to provide no examples of implementation.

    This is very interesting to me, but it would help your argument if you provided how the original Gogot example would be rewritten.

  • The nice thing about turns is that they can be represented by an unsigned integer. For example with an 8 bit unsigned integer:

    - 0000_0000 = 0 or tau

    - 1000_0000 = pi

    - 1100_0000 = 3*pi/4

    And the addition and multiplication by integer scalars all apply and the overflows work naturally. I wrote a little library in rust [0] to help with this as you can define the operations */+-% etc.

    [0] https://docs.rs/turns/latest/turns/

  • Ooh! that overflow is so clever. I would have been proud to have thought of that. Perfect fit for modular arithmetic.
  • > But math never decreed that sine and cosine have to take radian arguments!

    If you don't use radians you have to add to add conversion factors everywhere to do calculus. Radians are the natural unit for sin/cos just as E is the natural base of the logarithm and exponential functions.

  • Having read over this entire conversation I feel that people are almost uniformly missing the practical impact of this, which is simply that you can write your own math in terms of "turns" as much as you like. Nothing stops you right now. Defining a sinT function that takes turns is trivial. And so on for all the functions.

    I haven't done much graphics programming, but what I did I did with tau rather than pi. You all seem to be arguing about whether or not you need to enter some parallel universe where all the math is completely rewritten or something, but you don't. It was easy. It didn't clash with the universe at all. I just used "tau" instead of "2 * pi". That's, like, it. That's all there is to it. "const TAU = 2 * PI;" and I was done with the conversion work. Similarly, all that is being suggested is that instead of "sin(2 * pi * (1/4))" you define something like sinT and write "sinT(1/4)".

    Seriously. That's it. You don't need to rewrite every math library in the world. You don't even need your math library to support it at all, these are not complicated wrappers. You don't need to redo the whole of calculus to worry about taking derivatives of it or whatever. Besides, degrees already has all the same problems and we use them a lot too anyhow. Having trig function variants that take degrees isn't that uncommon, this is just another variant. You don't need to go in to your math library and remove everything that isn't based on turns. You don't need to force it in the face of the user of your code.

    It's true that the benefits of this approach are modest but the costs are way, way less than a lot of the posts seem to be arguing about. The costs are a few local function definitions and a new possible unit for the programmer to have to think about. How expensive that is depends on the local programming language and whether or not you can press the type system into service to represent units in a sane way, and even that is not a problem created by this proposal because I'd want radians and degrees isolated in the same way already.

    If you are programming in a language or environment that has no (practical) way to encode the units into the type system, and you had a program that settled on "every angle is radians" I don't think I'd introduce this into my code base. But if you have something where you can very easily integrate it with the existing code and get very solid guarantees that my new "turns" unit is compile-time guaranteed to never mix with "radians" or "degrees" I'd definitely consider it.

    by jerf
  • One would reap the most benefit if libraries were compiled late for the compiler to optimize away adjacent conversions and back.

    With C++ template libraries one can do that but compile times can become a hell.

  • The problem is that trigonometric functions are used in many more fields beyond geometry. The input is not always an angle around a point in euclidean space, it could be phase angle of a periodic signal. You can make an alternative set of trig functions that take turns, but you will anger a lot of people if you mess with the vanilla trig functions.
  • Functions are free. Create new ones. Sin1 instead of Sin, Cos1 instead of Cos.
  • You'll have to bring in the 2π factor somewhere. Cant escape it. If sint is the sin function but with angle give in turns, then d/dx sint(x) = 2π cost(x). sin(x) ~ x for small x but sint(x) ~ 2πx for small x.
  • When dealing with waves you often are dealing with turns - or, as they’re called in that world, cycles. A cycle is a turn is tau is 2pi.

    The SI unit for frequency after all is Hertz - cycles per second - which should really be considered equal to 2pi s^-1, but for complicated reasons, often isn’t, and most formulae that involve frequency ignore the ‘cycle’ - or it’s also hiding inside the definition of something like the wavelength or the Planck constant where it cancels out.

    Meanwhile the SI unit for angular velocity is radians per second which is dimensionally equivalent to s^-1.

    That said a becquerel, which measures rate of discrete events, is also dimensionally s^-1. (Next time you are measuring traffic to your website consider using the appropriate SI unit for measuring requests per second: the Becquerel.) - so dimensional equivalence isn’t the same as equivalence. You wouldn’t add a rate to a frequency, same as you probably shouldn’t add a torque to an amount of energy.

  • I argued this idea to a couple of my classmates when I was a physics undergrad, and they agreed. However, I later changed opinions because of what this does to the derivatives/integrals of your trig functions.

    For general periodic functions, [0, 1) is a good domain. But circles and spheres are geometric objects, and radians/steradians are geometrically significant units that are well suited for general purposes.

    I do remember that Doom uses an interesting alternative representation where an angle is a u16 multiple of `(2 * pi) / 65536`. Fixed point is sometimes a good choice in games and simulations due to having uniform precision.

  • Very bold title! Turns are very convenient until you need to calculate a rate of change, as of course d/dx sin(2pi x) = 2pi cos(2pi x). Unfortunately this is a common enough problem that I will be sticking with the radian.
  • but surely u differentiate by turns?
  • It depends on your context, and is mentioned in the article. The advantage of turns comes from the fact that the implementation of sinᵣ etc. is internally doing a conversion to turns, so by using sin_turns directly, you avoid calculating π/π with every call.

    It’s not a call for someone doing calculus or solving differential equations to abandon radians, just for the particular case of getting a numerical value for sin, cos, etc. from a library, having direct access to a turns-based function would produce faster code and also avoid some of the rounding errors that come from that π/π not to mention the imprecision of any angle that isn’t 0.

  • I feel like that approximates how I learned math. In geometry or trig you can use degrees or turns or any other unit, but almost never radians because that's harder write. As soon as you learn calculus, you switch to radians and never go back.
  • Let's do a full circle.

    It all began with replacing frequent occurrence of 2π in calls of sin and cos functions with τ.

    This post suggests an optimisation by getting rid of τ by getting rid of radians. That way one can get rid of frequent and adjacent radians to degrees conversions and back.

    I say, let's get rid of sin and cos itself !

    Of course I am being over the top here. However, if you represent angle not as a scalar in degrees, radians or turns but as a tuple (sin, cos), one can usually dramatically reduce the number of calls to trigonometric functions. Rational polynomials and square root suffices. Recall rotation is a linear transformation with a matrix whose entries are in terms of sin and cosine.

    As an API it might not be convenient but consider converting angles internally into a tuple of sin and cosine and keep it that way if your code frequently calls trigonometric functions.

    (Aside: Sometimes I prefer keeping the tuple in terms of half angles. Tan half theta is nice to have. And I am embarrassed by the number of comments I have made on this post)

  • That will introduce an interesting new bit-bending avenue since almost all tuples of floats are not valid angle representations in that form.
  • >As an API it might not be convenient but consider converting angles internally into a tuple of sin and cosine

    My friend,

    it's called a complex number. A unit complex number, to be specific.

    >Recall rotation is a linear transformation with a matrix whose entries are in terms of sin and cosine.

    That's what multiplication of complex numbers is.

    Can't wait till people here rediscover that a 3D rotation matrix has an axis-angle representation whose composition is given by quaternion multiplication.

    At that, children, is why learning mathematics is important.

  • HN has clumsy filtering, but you're allowed to write π and τ.
    by kps
  • If you want a single number (e.g. you are trying to serialize a lot of data), in many contexts you can replace the coordinates (cos θ, sin θ) with the stereographic projection h = tan ½θ = sin θ / (1 + cos θ). Converting back and forth between these representations is cheap and easy: cos θ = (1 − h²) / (1 + h²) and sin θ = 2h / (1 + h²).
  • I like to store angles as turns in my own code, because (as noted) it makes quarter-turns computable without rounding. OTOH if you need, say, twelfths of a turn, you might want to just store angles as degrees since that’s already common.

    Michael Spivak, in Calculus (3rd ed p. 301) considers the unit choice to be a property of the function and initially defines sin° and sinʳ (before settling on sin meaning sinʳ) and considers “sin x°” and “sin x radians” to be misleading, saying that ‘a number x is simply a number—it does not carry a banner indicating that it is “in degrees” or “in radians”’. I don’t really understand this argument, since in science and engineering we constantly carry units around with our quantities.

  • I don't think of it as units (as the sibling comment pointed out, angles are dimensionless); I think of ° as a postfix unary operator that does the conversion. In other words, I read sin(x°) as a shorthand for sin(x*Pi/180).
  • You generally can’t apply functions to dimensional units. The only thing units can do is be multiplied or divided together. So I can multiply a mass by a distance or divide a distance by a speed, and I can multiply the result by a scalar; but I can’t take the sine of a distance or the logarithm of a time or exponentiate a mass. Those are things I can only do to scalars.

    ‘But wait!’ You may cry: ‘the formula for a transverse wave varies with the sine of a distance!’

    To which I would say no: it varies with the sine of a distance (the horizontal displacement), divided by another distance (the wavelength), divided by 2pi. The distances cancel out and leave a scalar. The sine is taken of that pure scalar; it results in a pure scalar; and then it’s multiplied by another distance (the amplitude) to give you a vertical displacement. Sine is a pure function.

    Something else to consider is that the way we combine units with scalars to create dimensional quantities is through multiplication - and it’s not like there’s a simple formula for what a sine of a product is - I can’t determine sin(ab) in terms of sines or other functions of a and b. So if, say, a ‘degree’ were some dimensional unit, sin(90°) would not be something I could calculate - despite knowing sin(90) I don’t know sin(°) - whatever that would mean - and even if I did it gets me no closer to figuring out sin(90°)

    Realizing that ° is just a mathematical constant equal to pi/180 solves a lot here.

  • It's because both radians and degrees are are a ratio of a length to another length and are thus dimensionless. No matter how you measure it, all angles are without a unit.

    It's most obvious with radians but it's also the case with degrees.

    Using radians, you are guaranteed to not introduce unusual extra terms to rescale angles, if you use any other scale of angle you will have to keep track of extra terms.

    That may be useful in whatever you're doing. I work in degrees quite often and I'm careful to keep track of the 2pi/360 terms that crop up all over the place. With grade measure you have to keep track of 2pi/400 terms and with turns you have to keep track of 2pi/1 terms that will repeatedly show up.

    Again, depending on what you're doing, this may or may not make sense to do.

    In general, mathematics works out easier when the scaling term is 2pi/2pi because then you have a lovely 1 scale factor you don't have to keep track of.

  • I think I cautiously agree with this notion to some extent, but IMHO the real answer is that it's application-dependent, and if you're writing a low-level trig library and you have to pick one or the other, it really isn't clear to me that turns should win over radians.

    I expect many systems that use trigonometry would sometimes use small-angle approximations either for efficiency or to bootstrap to the general case. It'd be natural to use Taylor series here, i.e.:

        cos(x) = 1 - x^2/2 + ...
        sin(x) = x - x^3/6 + ...
    
    If you've committed to representing all trigonometry in "turn" units, then you instead need to use:

        cos(2 pi t) = 1 - (2 pi t)^2/2 + ...
        sin(2 pi t) = (2 pi t) - (2 pi t)^3/6 + ...
    
    In this case it would be less accurate and efficient to force everything into turns if you ever need to work with radians.

    Closely related to this, if you ever need the derivative of a function that does trig (e.g., in numerical optimization), you may as well use radians because if you don't, any extra factors you apply will appear in the expressions for the derivatives and you'll have to deal with them there anyway.

    Basically for that reason, it's pretty clear that trigonometry in terms of radians is the "correct" convention mathematically speaking (away from computers), since derivatives of the radian-based trig functions are so easy to express. Given that, if we have to pick one convention...isn't it less confusing to use the same thing everywhere? That said, there are interfaces that provide both versions, and since as the article points out there are cases where the turn-based versions can be more efficient, that's probably the right way to go.

  • Why are math libraries consistently treated as space hogs if you don't keep them as barebones as possible? I've had sinDeg/cosDeg overloads for a while and I don't see why they can't be built into the base library; the same would go for a sinT/cosT that takes turns instead of radians or degrees. Why do we have to pick one and meticulously avoid having multiple?
  • The time where "turns" are really great is when a whole lot of what you're doing is a phase accumulator.
  • I don't have a super-wide gamut of experience here and numerical analysis isn't my specialty, but nearly all trig implementations I've looked into (in both software and hardware) make heavy use of lookup tables and other shortcuts. I've never seen a Taylor series used in a general implementation - not saying it doesn't exist anywhere, but in most cases that I'm familiar with you could support turns just as easily with a different lookup table.
  • The math is definitely not fine with turns, because your Euler formula e^ix = cos x + i sin x no longer holds. We can use a base other than e, namely B = e^2pi which around 535.4916. This doesn't have the nice e properties like d/dx e^x = e^x.

    The elegant fact that the base of the natural logarithm, which produces an exponential function that is its own derivative, also shows up as the basis for the above Euler's formula, shows that radians are special: like what binary is to computers.

    The natural logarithm being its own derivative is in fact directly linked to the derivative a radians-based sin(x) being cos(x) and so on. Make it any other unit, and you have a mess of conversion factors worse than 2pi.

    Imagine complex chained derivatives, double and triple derivative, chain and product rules, all stuffed with trig functions and generating gratuitous piles of cascaded conversion constrants because radians were not used.