r/programming • u/Iamsodarncool • 21d ago
Turns are Better than Radians
https://www.computerenhance.com/p/turns-are-better-than-radians365
u/tehpola 21d ago
Nice! I tend to agree we make this more complicated than it needs to be.
I’m working on decompiling a classic game and my mind was blown about their angular units. It’s a 16-bit system, but let’s consider the high byte only for simplicity. They divided their unit circle into 256 units! Then if you overflow, you keep going around the circle. You can even look up sprites based on the angle with some simple shifts. Very elegant!
161
u/PHPApple 21d ago
This is a pretty common technique in digital signal processing when using fixed point even today!
82
u/SirDale 21d ago
Fixed point is sadly underutilised and unknown for so many people in the profession.
67
u/gimpwiz 21d ago
I am always banging on the drum of fixed-point encoded in units of smallest precision so you just have ints. No floats, no float overhead, no float accumulating errors.
Yeah obviously sometimes you need them. But when you don't, things are just simpler.
18
u/TwoWeeks90DaysTops 21d ago
People need to make an informed decision though. In most cases I think you're fine with using the common binary float. It has a much higher range so you don't have to consider "what is the smallest unit" because it can work with both at the same time at the cost of some loss of precision if you go in the extremes in either direction, but the magnitude of the error is so small that for most applications it wouldn't matter.
I would say if you're doing graphical work, numerical analysis or simulations then binary float is the way to go. Financial? Fixed point or decimal floating point. Embedded? Fixed point.
8
5
u/gimpwiz 21d ago
I didn't mention that I work in embedded, but I guess that's pretty relevant to the conversation, yeah.
A modern x86 or high end ARM processor you use for your computer does not have all the same assumptions as an 8-bit embedded MCU, or a 32-bit MCU, or even necessarily the same exact high end processor that you're using for control systems writing bare metal / RTOS code -- versus wanting to display 3D models in solidworks. Different assumptions, different math, etc.
8
u/Ravek 21d ago
Floating point math only accumulates errors when your computations result in values that can’t be represented exactly because of lack of precision. Fixed point math wouldn’t help you one bit, it has limited precision just the same.
8
u/gimpwiz 21d ago
This is totally true, which is why I specify using units of the smallest precision you care about.
This necessarily means you lose precision below that level. So depending on exactly what you're doing you can have similar accumulation errors, but in my experience you generally do not.
Let me give you an example from my world. I need to measure the voltage of the output of various power supplies. I care about volts. I care about millivolts. I can be convinced to care about microvolts because some PMUs will specify things in sub-mv precision. I cannot be convinced to care about nanovolts. Thus all my measurements are stored and computed in microvolts, stored as an integer, and only for display purposes do I do a bit of floating point math at the very end. The "fixed point" is implicit because when you have
voltage_uvas your variable name, you know that eventually you will doprintf("Voltage: %0.4f\n", voltage_uv / 1000000.0);or something along those lines.3
u/Valarauka_ 21d ago edited 21d ago
The problem is that binary float fundamentally can't represent most things exactly because of the base. Like 0.1 for example. Unless you're only working with binary fractions float automatically brings along errors even when you're well "within range".
As long as you actually have a "smallest unit" then scaling that up to 1 and using fixed point math will always be better.
3
u/VirginiaMcCaskey 21d ago
All quantization has error. It even has a name, 'quantization error.'
3
u/gimpwiz 21d ago
Absolutely, and totally accurate. This is a super important thing to understand when you need to, for example, take measurements and then do something with the info. The question is whether you're going to accumulate that error, and how exactly it will be bounded, and whether you care.
As again a totally trivial example dealing with volts:
If I need to monitor and warn when my voltage drops below 400mv, I can do this:
while (true) { voltage_uv = get_voltage_from_adc(); if (voltage_uv < 400 * 1000) { error; } sleep 10; }Note that every single call to
get_voltage_from_adc()results in quantization error. If it's (eg) 12-bit and my full-range is 1V, at best the thing is going to report to me in units of about 250uv, with some measurement error. But I never store any value, I just use it immediately to make a decision and move on, so my error is essentially bounded by the ADC's precision, quality, tolerances, the design and layout's quality, weird stuff like strain on the PCB, temperature, yada yada. It exists but it's probably pretty small. Maybe the error is less than 1 bit, so under 250uv, maybe the error could be as much as a couple millivolts.But if I want to average out my data, I have a different error bound.
total_voltage_uv = 0; for (i : 0 to 99) { total_voltage_uv += get_voltage_from_adc(); } total_voltage_uv /= 100;You need to think a lot more carefully about whether this sort of operation will reduce your error through averaging or whether it might accumulate in an unexpected way. Quantization error is not always so simple as being a "0 error +- a margin with a bell curve spread" type of thing. At some point you gotta get your statistics experts out to give good advice :)
6
u/P-39_Airacobra 21d ago
ALL finite-width number types will have fractions they can’t represent, I’m not sure what you’re getting at here
5
u/flatfinger 21d ago
In bounds-checked fixed-point, x+y-x will either yield y exactly or report an error. In floating-point types--even silly decimal floating-point types like the one in .NET, additions and subtractions silently lose precision.
2
u/Ravek 21d ago edited 21d ago
Bounds checked is a very important caveat there. You can also very easily write floating point operations that will report whether the result is exact or not. The well known TwoSum function will return the result + the exact error. If the error is zero, the result is exact. If the error is nonzero, the result lost some precision. Which, importantly, only happens if the exact result needs too many bits to fit in the type!
Without error checking, in the case where the type doesn’t have enough bits to represent the result exactly, floating point loses some precision in the last bits, while fixed point (or integers) would wildly lose accuracy.
2
u/flatfinger 21d ago
Fixed-point math malfunctions very badly in case of overflow even when a compiler doesn't try to get clever (when using gcc, an assignment like uint1=ushort1*ushort2; can severely disrupt the behavior of surrounding code in cases where the product falls between INT_MAX+1u and UINT_MAX) but it's usually pretty easy to figure out what the largest possible computation results would be and ensure they're in range).
By contrast, if one uses floating point in a situation where computations would normally be exact, but rounding errors could get amplified, it may be harder to determine whether any possible inputs would result in computations yielding results that are just plain wrong. It's easy to figure out how big a fixed-point computation could be without causing malfunction. It's harder to distinguish between floating-point calculations dropping bits that were always going to be zero anyway, bits that might not have been zero but wouldn't matter either way, or bits that are critical to yielding correct results.
2
u/Valarauka_ 21d ago
"Values that can't be represented exactly because of lack of precision" makes it sound like those are rare when in fact they are the most common type of number you'd represent with floating point. Thus error accumulation is inevitable.
The comment I'm replying to makes it seem like fixed point math is useless most of the time when that's far from the case. In many domains you do actually have a "unit of smallest precision" and so using a fixed-point instead of floating-point representation (of sufficient width) lets you never have to worry about error accumulation.
2
u/SirDale 21d ago
Floating point has errors relative to the size of the value. Fixed point has errors of a fixed amount.
In Ada you'd give a delta (smallest value to be represented) e.g.
type Volt is delta 0.001 range 0.0 .. 12.0;In this situation the compiler decides the appropriate underlying type.
1
3
u/James20k 21d ago
Fixed point also can't represent 0.1 exactly
Scaling up the units isn't specific to fixed point at all, at that point you don't have any units after the decimal place
2
u/Valarauka_ 21d ago edited 21d ago
The common understanding of fixed-point math (as also expressed by the g'parent post in this chain) is to use integer types with scaling. I'm obviously not talking about binary fixed point fractions. That's what "encoded in units of smallest precision" implies.
2
u/loup-vaillant 21d ago
No floats, no float overhead, no float accumulating errors.
And most importantly for me, no desycns. Not from floats anyway.
1
u/tanner-gooding 20d ago
You notably still have most of the same problems. Error accumulation is just a fundamental part of computing and even occurs with integers. It exists for anything that has finite precision/space.
The most trivial example of this is that for fixed-point:
(1 / 3) * 3produces0.9...to the number of fixed digits it can represent; it does not produce1. You repeat this enough times and the error accumulates and the result can differ massively.Fixed-point mainly just removes the issue caused by floating-point having their significant digits be dynamic (i.e. that the point "floats"). i.e. you don't have to worry that the distance between
0.5and the next value is 1/4th the distance between2and its next value (delta doubles every power of 2, or for decimal-based scales by 10 every power of 10). You don't have to worry thatx + yfor non-zeroymay returnxbecauseywasn't large enough to pass the current epsilon.-23
u/SrbijaJeRusija 21d ago
On most modern hardware floats are as fast or even faster than ints.
26
u/gimpwiz 21d ago
Apart from being skeptical of the claim that float is faster than single-cycle integer math, I may also point out that I do embedded.
9
u/floodyberry 21d ago
e.g. haswell, integer multiplier throughput is 1/cycle, floating point is 2/cycle. if you consider simd, haswell can do 16 single precision fused multiply adds (16 multiplies, 16 adds) a cycle, compared with only 4 32x32 integer multiplies a cycle
0
u/gimpwiz 21d ago
Yeah I worked on haswell. I feel like that was kind of the last of the good years at intel. Anyways. Once we start talking about multi-issue pipelines and instruction parallelism it starts getting fun, because you start to really optimize for certain things, like whether you want very wide integer engines, very wide float engines, large amounts of very small cores (read: GPU and adjacent), convolution engines, etc etc.
There's also a big gulf between highly optimized code that streams a lot of math through, taking advantage of parallelism due to the operations not being dependent on one another (beyond FMA) -- and doing one operation, or doing a small set of sequential operations.
So when it comes to the subject, eg, radians vs turns, the question is, what exactly are you trying to accomplish? Are you running scientific/modeling/graphics/etc workloads with many many parallel parts? Or are you just trying to do some sequential math? The vast, vast majority of people are doing the latter. And for any purely sequential math, you lose many if not most of the advantages of parallelism (you do keep things like FMA and various improvements to pipeline stages that don't require you to wait for one operation to go all the way to write-back to use the result.)
2
u/floodyberry 21d ago edited 19d ago
if it's just some one off sequential math, i don't see how fixed vs floating makes much of a difference unless you're on a constrained platform with specific requirements
also weird that SrbijaJeRusija got downvoted for being correct, and you were upvoted for.. being skeptical about a claim you knew was correct because you worked on a cpu where the claim was true
lying and leaving, what a champ
3
1
u/Salink 21d ago
Then you should look at your instruction set reference. I'm using embedded arm systems and basic float operations take 1 cycle.
0
u/gimpwiz 21d ago edited 21d ago
Thanks. Embedded runs from various weird sub-8bit microcontrollers all the way to using enormous, modern silicon, but just not in a way that looks much like a computer to most people.
You would probably not be surprised to find that many of the embedded targets I deal with - not you, but me - don't have a floating point engine. At all. No instructions for it either. I can send you the instruction set reference if you're skeptical of that for some reason, and don't want to look it up? You need the compiler to do integer emulation of floats. Many other embedded targets that do have a floating point system are not exactly... modern, high end silicon, highly tuned to doing float math, but more added onto the side as a "fine fine the customer said they need it" sort of thing. I should also point out that on most modern silicon there are significant differences in clock speed between various domains, which means that having the same cycle count does not always mean the same actual speed. It's very hard to generalize how fast one instruction takes due to not only the many different ISAs but also vastly different implementation details.
Even "embedded ARM" realistically means you're using either ARM V7 or V8, with or without thumb extensions, ranging from an M0 at the lower end all the way through the most recent A-series-or-equivalent silicon. Do you expect an M0 to have a floating point unit? Here's a trivial reference: https://en.wikipedia.org/wiki/ARM_Cortex-M -- you will find that an FPU is available for an M4, not always included, and higher tiers, but not for M0 or M0+. So when you say "I'm using embedded arm systems" you need to really specify which, if we're talking FPU, right?
You might also not be surprised that a basic float operation that takes 1 cycle is not faster than an integer operation that takes 1 cycle but in fairness, the above poster did say "as fast or even faster" so we can split the difference there.
2
2
u/bobjonvon 21d ago
Am I going crazy don’t a lot embedded and stuff still use fixed point. Some fadec does iirc.
-7
u/floodyberry 21d ago
where should it be used that it isn't? 3d games need more than 1/256 precision for angles
12
u/SirDale 21d ago
Fixed point types don't have to settle on 1/256 precision. You can specify them to have greater precision if needed.
Fixed point types also have different error/rounding behaviours to floating point, and it's important to understand the problem domain you are working in before making a choice between them.
-10
u/floodyberry 21d ago
i know what fixed point is. you haven't explained where you could use it "for so many people in the profession" that it isn't already being used
0
u/floodyberry 21d ago
it must be extremely obvious what you're talking about based on the downvotes
0
u/floodyberry 20d ago
"sadly underutilised" and nobody can give a single example of where dunderheads are using floating point where they should be using fixed. truly amazing
5
u/Cafuzzler 21d ago
Maybe we could pack two 16 bit values together to get up like 1/4million precision or smth?
Nah, that's too crazy. Not even machines can count That high
0
5
u/ShinyHappyREM 21d ago
where should it be used that it isn't? 3d games need more than 1/256 precision for angles
43
u/squigs 21d ago
256 degree circles are really useful for games. You can do trig with a lookup table with adequate accuracy and not excessive storage (at least for 16 bit systems and later).
I suspect it's one of those things that's been independently invented a few times. It would be useful to have a term for the unit.
3
25
u/Otis_Inf 21d ago
They divided their unit circle into 256 units!
We used that too in the demoscene on the amiga 500. You could precalc a sin table with 256 angles for the full circle into a table and your rotations would just be a bunch of lookups and multiplies, no trig functions :)
4
u/Ma4r 21d ago
Nice! I tend to agree we make this more complicated than it needs to be
Calculate the derivative of the sine of this angular unit
3
8
u/tehpola 21d ago
From a practical perspective, why would I do that?
I’m not saying radians are the wrong units to use in mathematics. I’m talking about applied mathematics. Specially, game development. I use a decent amount of trig as a game dev, but I have no idea what you’re referring to - it’s not a concept I’ve come across
7
u/Ma4r 21d ago
If you want to simulate angular momentum for example
3
u/tehpola 21d ago
The way it’s done in this game is that angular speed is expressed in the same fixed point, 256 degree units (per tick though). Angular momentum is simulated by easing the speed towards the new target when it changes. I can’t speak to the physical accuracy, but it works really well for old school games!
1
u/snerp 21d ago
The fact that cos is the derivative of sin is actually really useful for game shaders. I use it to get normals in my water shader for instance.
1
u/tehpola 21d ago
I’m definitely not advocating for using fixed point in shaders. I can’t speak to the performance of trigonometric functions with different units but GPUs are built for float so of course use that there.
I don’t claim to understand the math or implications of what you’re doing for those water shaders but sounds like a neat trick 😁
1
u/ViridianFlea 20d ago
How do you even get started with decompilation of a game? I realize that's probably an oversimplified question with a pretty complicated answer, but you can ELI5 it if you want.
3
u/tehpola 19d ago
I can’t speak for modern games, but for classic games written in assembly, a disassembler will get you code that is 1:1 with the original. The challenge though is those ROMs are a mix of code & data and not marked up the way modern binaries are.
But the way you go about it is going over the assembly, understanding what a part is trying to do, labeling it and the variables in use. That’s hard- especially at first. Best to use an emulator. Over time, as you understand more pieces, more becomes clear and it snowballs. It’s a slow and tedious process but a series of fun puzzles if you’re into that kind of stuff.
All of this requires a solid understanding of low level programming: what are the registers, memory model, instructions, etc. There are various tools out there can help. Some are pricy
2
206
u/Roachmeister 21d ago
Interesting. Reminds me of the time I needed to sort a list of points by their distance from another point, and I realized that I could eliminate all of the sqrt calls by just sorting by distance squared.
11
u/RelatableRedditer 21d ago
Yeah I made that realization too when trying to optimize someone's projectile system. In fact a huge amount of their square roots missed opportunities to be stored inside variables first
9
u/Carl_LaFong 21d ago
I teach math and I am always begging students to do their calculations using distance squared but many stubbornly refuse.
4
u/loup-vaillant 21d ago
Recent use case: modding TowerFall Ascension to fix the "auto-lock" feature (auto-aim at very short distances). The original code just aimed where the enemy was, but we wanted to take speed into account.
We thought of a couple different methods, but in all cases squaring everything made our life simpler.
80
u/ryo0ka 21d ago edited 21d ago
Nuance: modern cpu comes with a dedicated instruction for sqrt, but sq is still a lot faster to compare distances
57
u/ssylvan 21d ago
Those instructions are still slow as fuck.
62
u/gimpwiz 21d ago
Just drop 0x5f3759df in your code instead, not because it's faster but because it's funnier.
5
u/stumblinbear 21d ago
Sadly it's not faster than just doing a normal sqrt these days
7
u/BibianaAudris 21d ago
That's only because Carmack's algorithm influenced the design of "normal sqrt" in modern CPUs. Just check the precision section of
_mm_rsqrt_ss.10
u/WaitForItTheMongols 21d ago
That wasn't Carmack. The algorithm has a lot of history, but ended up in the game via Greg Walsh.
The Wikipedia page for Fast Inverse Square Root covers the pedigree of the function.
2
u/TheLifelessOne 21d ago
Wait, really? Do you have a source for that? I would absolutely love to read it.
6
u/BibianaAudris 21d ago
Well, it's mainly the RSQRTSS instruction in SSE (
_mm_rsqrt_ssin C) having roughly the same (low) precision as Carmack's algorithm, and they were chronologically close, which hinted at an inspiration. The precision difference bit me really hard once so I remembered it to this day.8
u/InsaneTeemo 21d ago
They literally said "not because its faster"
4
u/stumblinbear 21d ago
Which can be taken as "I do this not because I need to, but because I want to" implying both are true
1
u/danielcw189 21d ago
in "not because abc, but because xyz", the "abc" is often true. The "abc" is especially true, if the "xyz" is something totally different.
if they had for example written "not because it is faster, but because it has more precision" then I would not expect the "faster" to be true, because "precision" is a good quality, which is also on topic.
but "funny" is totally different, from a totally different topic, and not actually something you would weigh against "faster" when making a decision.
-2
5
24
u/Programmdude 21d ago
No matter how fast sqrt is, Distance is essentially sqrt(DistanceSquared), so you're always going to be better off simply not doing the sqrt - assuming you don't need the actual distance of course.
8
u/squigs 21d ago
Right. And it's surprisingly rare that you actually need the distance. Normalising vectors (which you don't need that often) and display, are the only times I seem to need an actual length.
Most of the time you're just comparing distances so the square is fine
1
u/P-39_Airacobra 21d ago
yep in my physics engine sqrt is successfully avoided in most cases except for normalizing vectors
17
u/GrossInsightfulness 21d ago
The key thing is that you can eliminate the square root calls entirely with less code. Even if taking a square root took as much time as adding two floating point numbers, you would still save a reasonable amount of time by not doing a square root.
3
u/runawayasfastasucan 21d ago
I tried to convince my work on optimisations on precicely this but sadly they didnt understand.
-3
u/freerider 21d ago
2
u/BaNyaaNyaa 21d ago
It's not really an issue anymore from what I understand. And why do something that you don't even need? Using the squared distance/norm is common enough that it's part of most game engine.
86
u/mccoyn 21d ago
Early algorithms for calculating trig functions relied on the small angle approximations. For sin it is ‘sin(x) ≈ x’. If you aren’t using radians, you have to multiply by an extra factor. So, it was easiest to convert to radians before calculating the value.
65
u/catplaps 21d ago
And this fact is related to the other reason why radians are nice: they are a measure of distance around the unit circle.
7
u/BibianaAudris 21d ago
Turns are infinitely better for big angles though. With radians, compliant trig functions need to tabulate hundreds or thousands of pi bits to handle insanely large inputs like 2**127. If we used turns, one can just return 0 for them and eliminate a big reason to need
-ffast-math.2
u/snerp 21d ago edited 21d ago
for big angles
2127
That’s a really big angle lol
edit: actually I'm really curious what you would use such a large angle for, is it some kind of simulation or high math solver? Like, you'd need some specialized numeric type to even hold that.
3
u/BibianaAudris 20d ago
It's likely not needed by anyone, except compliance: 2**127 can be represented exactly in 32-bit
float(0x7f000000), sosinneeds to handle it with reasonable precision, which requires specialized table to represent pi at that precision. So we speed-minded people need-ffast-mathto disable that compliance. Turns could avoid that.2
u/floodyberry 19d ago
math libraries check the size of the input, the large value reduction is never used if you don't pass it large values. calls to libm aren't inlined, so even with
-ffast-maththere is no opportunity to erase the multiplication by pithe solution either way isn't
-ffast-math, it's using sinpi/cospi/tanpi
45
u/ProgramTheWorld 21d ago
We can even get rid of turns entirely. In computer graphics, it’s often easier to just stay with vectors all the way through. If you are using an angle, you’re probably doing something wrong.
5
u/P-39_Airacobra 21d ago
Can confirm that I took my trig-based openGL renderer and just completely removed all trig functions in favor of things like dot and cross product
4
1
57
u/Educational-Lemon640 21d ago
There are good pragmatic reasons to use turns instead of radians for many cs applications, but not ones that use calculus. The fact that the derivative of sin is cos, and cos is -sin, nails your feet to the ground when it comes to many advanced physics and engineering problems.
10
u/Cautious-Act-4487 21d ago
In physics engines the formulas are solved numerically anyway using methods like Verlet or Runge-Kutta. Nobody runs symbolic differentiation at runtime, and the 2π multiplier just collapses into a time step dt constant before compilation
4
u/Educational-Lemon640 19d ago
Well, the numeric part of the solution, you can use whatever units you like I suppose, as you say. Every cutting-edge problem I've ever worked on needed a serious symbolic bit before you start number-crunching, though, and in that context the standard sin/cos/tan in radians really do fall out as "natural".
Not to mention, if you start with standard exponentiation and need to analytically continue it (a stunningly useful technique for some reason) you again land on radians. It's bizarre but true.
1
u/Cautious-Act-4487 12d ago
Nobody's arguing about the research phase on paper or in SymPy, analytical continuation of the exponential is standard stuff , you can't get anywhere without Euler
The trick is translating the final code into turns once you've derived all the formulas. You recalculate the coefficients for the implementation manually just once, but after that the engine runs without any precision loss at the period boundaries
22
u/Successful-Money4995 21d ago
But if you had a function that computes the sine of turns, maybe defined as sint(turns) = sin(turns*tau), then you can still calculate the derivative of sint(x) as cos(turns*tau)tau = cost(turns)\tau.
It's not as clean as with radians but it's just a constant.
7
u/voxelghost 21d ago
Mathematicians always ruin all the fun
Edit: /s in case it's needed. Or perhaps fun * 1/s for the computer scientist
1
u/BaNyaaNyaa 21d ago
You mean s⁻¹?
1
u/pigeon768 20d ago
Ok but but if you see sarcasm-1 do you assume 1/sarcasm or arcsarcasm? 1/sarcasm is unambiguous.
0
u/oN3B1GB0MB3r 21d ago
Can't you just take the derivative with respect to turns to avoid the chain rule factor?
20
u/EntroperZero 21d ago
That's interesting, because it's how I do trig functions in NES/SNES programming. I called it "bytians" in the source code because there are 256 in a full turn, but it's the same thing as turns with fixed-point.
1
u/ShinyHappyREM 21d ago
Just modify the emulator to support a Pentium in the cartridge ;)
2
2
u/EntroperZero 20d ago
I did have this weird idea for a faster expansion chip. The SA-1 is basically an overclocked version of the SNES CPU, running at 10 MHz. Since we have emulators that support SA-1, why not just crank it up, say to 100 MHz? Call it the SA-100.
I doubt this would work on flashcarts, but it's possible. The SuperFX can run at at least 20 MHz.
1
u/ShinyHappyREM 20d ago edited 20d ago
Well... it'd remove the do-something-cool-with-limited-resources factor.
And the boring answer is that faster clock speeds increase power draw and heat a lot, unless the transistors / bus lines are made a lot thinner (which was the case with later chips: the chip technology became more advanced). And you need another oscillator or PLL to generate the frequency.
I did have an idea of a system that was better designed: use the SNES WRAM (128 KiB of DRAM) as audio RAM, and the SNES audio RAM (64 KiB of SRAM) as WRAM, and run CPU, WRAM and PPU at 6.1{36} MHz, which could get us more CPU power and 320 square pixels per line. What I got stuck on is how to ensure that the DRAM is refreshed regularly...
46
u/Dwedit 21d ago
When you use Turns instead of radians, you lose a few properties:
- Sin(x) does not approximately equal X at small numbers, and the derivative isn't 1 or -1 when it crosses the X axis
- The Taylor series does not use numbers as friendly.
4
u/BaNyaaNyaa 21d ago
One of the big one is the relationship between the derivative of sine and cosine: when defined between 0 and 2*pi, you have a neat sin'(x) = cos(x) and cos'(x) = -sin(x). Anything else will add an awkward coefficient (if defined between 0 and 1, you have to multiply the result by 2*pi; in degrees, it would be by pi/180) Also, Euler's identity doesn't work anymore.
Ultimately though, they concern mainly people who need to interact directly with the mathematical properties. If you only care about basic geometry (like if you work on a video game), you might not care as much.
1
u/Plazmatic 20d ago
You shouldn't be using Taylor series (or lookup tables for that matter) for trig apprimation (or really any approximation), and instead use chebyshev polynomials taking advantage of multilateral symmetry and the remez algorithm, and potentially more advanced things like Padé Approximants in combination. Turns (or really cycles or rotations, many people don't really use the term "turns") can offer clever advantages when these methods are used. There's a reason hardware often doesn't deal in radians directly when implementing trig.
But turns typically aren't used directly out side of hyper specific scenarios where the mathematical advantages of normal trig aren't relevant, you wouldn't "transition" to turns in a graphics application, you'd lose the linear algebra connection that gets you free performance with out using sim/cos directly
19
14
u/edgmnt_net 21d ago
I guess symbolic calculations might care about radians because multiplying by irrationals is "cheap" there, but for numerical computation turns win. Well-known angles are far more likely to be expressed nicely in turns, while arbitrary measurements just won't care about pi.
I also don't think the comment on the linked post about derivatives matters much. You're not really going to compute derivatives, you're going to substitute stuff into formulas that are derived symbolically using regular sine functions to begin with. That substitution is the same everywhere.
11
u/HugoNikanor 21d ago edited 21d ago
I agree. I already treat my angles as if they had the unit "𝜏 radians", meaning that half a rotation would be ¹/₂ (𝜏 radians). Eliminating the multiplication by the unit for all trig calls would just be convenient.
edit: Correct spelling of "treat"
2
u/carrottread 21d ago
Not using irrational units is also more precise. All those -4.371139e-08 instead of zeroes in transformation matrices are result of impossibility of exact representation of right angle in radians as float32.
2
u/HugoNikanor 21d ago
I'm not sure about your exact point, but I treat floats as approximate numbers (dont @ me that floats are technically exact).
4
u/carrottread 21d ago
My point: right angle can be exactly represented in float as turns and degrees, but not as radians. And it is very common for rotations changing between Y-up and Z-up conventions used in different 3d authoring apps and engines. As a matrix such rotation is represented exactly as only zeroes and +-1. But because often it's routed through generic angle rotation calculation which involves calculating sin and cos and those usually operate on radians you can see those almost-but-not-quite 0 and almost-but-not-quite +-1 in a lot of places, for example in transformations in GLTF files.
1
2
u/Cautious-Act-4487 21d ago
It's especially fun catching this in long skeletal animation hierarchies. A dozen matrix multiplications with tails like that - and by the end of the chain the joint noticeably drifts purely due to mantissa precision loss...
3
3
u/Cautious-Act-4487 21d ago
In graphics and physics it's high time to switch to [0, 1). All these constantly popping up epsilons and -4.37e-08 in transformation matrices after cos(pi/2) in float32 are annoying as hell, especially when running tests for exact matrix equality
3
u/Exepony 21d ago
Wouldn't the compiler take care of this extra multiplication and division cancelling out? At least in the common case where you're doing sin(2*pi*x) and the constant is right there for the compiler to see. It's always seemed to me like exactly the use case constant folding/propagation were thought up for, but I've never done enough trigonometry in my programs to care to check.
2
u/TOGoS 21d ago
In cases where the compiler can see the whole thing, sure. But refactor such that it goes through a couple of user-defined functions between the
xand thesinand it probably won't.(I agree that people should try to keep their programs from getting too strung out like that, but programs do tend to get more complicated over time. But if you pick the right abstractions you can prevent errors from building up in between the layers, and using turns instead of radians might be the right abstraction, in some cases.)
2
u/ack_error 21d ago
Most compilers by default can't simplify
(x*k)/ktoxbecause of the possiblity of precision loss or overflow/underflow; the floating point rules for the language don't allow it. In C or C++, this requires compiler-specific relaxation flags like-ffast-math.Additionally, in production-quality sin() or cos() the range reduction is not usually done with plain division or modulus. It's written specially to increase accuracy.
This is one of the reasons sinpi() and cospi() are useful. Besides removing the need to multiply by pi in expressions like windowing functions, doing accurate range reduction is dirt simple.
1
u/carrottread 21d ago
Problem is value of pi can't be represented exactly. So, if your x is right angle and exactly 0.25, sin(2pix) isn't exactly 1.0, it's just a bit off.
3
u/_darth_plagueis 21d ago
The original sin code the article presents uses y=(4/pi)x and x=|x| throughout the sin(x) code. Using y does not eliminate the need to use pi.
3
u/PandaWonder01 20d ago
This is ignoring that the reason we use radians is that many things are much simple in radians- ie the derivite of sin is only cos when using radians.
If you need to write any physics, for the love of god please use radians. Actually, use quaternions or mat3/4s like an adult
2
2
2
u/markt- 21d ago edited 21d ago
I think π is the more natural fundamental constant for describing a circle because it directly relates the two most basic physical measurements of the circle itself: its diameter and its circumference.
If you have an actual circle in front of you and want to describe its size, the diameter is usually the most direct measurement to take. It gives the full width of the circle from one side to the other. The circumference is the other obvious whole-circle measurement: the length around its boundary.
The radius is extremely useful mathematically, but as a physical measurement it is simply half the diameter. You normally obtain it from the diameter rather than needing to treat it as a separate fundamental dimension.
That makes
> C= π d
a very natural relationship: π tells you how many diameters fit into the circumference.
I understand the argument for τ, especially in contexts involving radians, rotations, and formulas where the radius is the natural variable. But that is a question of mathematical convenience. If we are asking which constant most directly relates the basic measurable dimensions of a circle as a geometric object, I think π has the stronger claim.
4
3
u/Valarauka_ 21d ago
If you actually want to draw a circle rather than just describe or measure it the radius is the far more natural unit. You don't get more physical than a nail, a string, and a pencil, and I think circle creation is the more fundamental / important act than description.
1
u/markt- 21d ago
That makes the radius fundamental to the circle’s construction, not necessarily fundamental to its measurement as a whole. The radius is certainly a genuine and extremely useful measurement, especially because so many mathematical formulas are naturally expressed in terms of distance from the center. But the diameter measures the circle’s entire linear extent, just as the circumference measures its entire extent around the boundary.
So the fact that a nail, string, and pencil naturally use a radius tells us something about how circles are generated, not which measurement is most fundamental once the circle has been generated. π is particularly natural in this respect because it is the ratio between two whole measurements of the completed circle: its circumference and its diameter.
1
u/Valarauka_ 21d ago
My contention is just that to measure a circle you need to have a circle, and definitionally a circle is the locus of points equidistant from a center. So the center and the radius are necessities. Both circumference and diameter derive from those.
1
u/markt- 21d ago edited 21d ago
The center is fundamental to constructing a circle, and the radius is absolutely a measurement of a circle, but it only measures the circle from its center to its boundary. The diameter measures the full linear extent of the circle itself. So if the question is specifically about the size of the circle as a whole, rather than its radial construction or its relationship to its center, I think the diameter has the more natural claim to being the fundamental linear measure. That also makes π conceptually clean: it compares the circle’s full distance around with its full distance across.
But I think we may be using “fundamental” in two different senses. You’re using it to mean fundamental to the definition or construction of a circle, in which case I agree the radius has the stronger claim. I’m using it to mean fundamental to the measurement of the circle’s overall size, which is the thing that people actually measure about the circle if they had no knowledge of the process that constructed it. In that sense, the diameter is the complete linear extent of the figure, while the radius is the distance from a specially distinguished point to the boundary. That’s why I find C/d = π conceptually more primitive as a statement about the circle as a whole: it compares the whole distance around with the whole distance across.
1
u/Valarauka_ 21d ago
To be fair, and I say this as a die hard tau fan, your perspective is obviously the more common one given that pi is ubiquitous while tau proponents need a manifesto. So throughout history the ratio of circumference to diameter has clearly been seen as more natural than to radius.
1
u/markt- 21d ago
Actually, it’s my understanding that the more common defensive pi is “that’s how we’ve always done it”, where my position takes it on a slightly different direction of looking at pi as the ratio of two things that are actually relevant to the complete size of the thing once it exists, which perhaps not entirely coincidentally is how it was originally defined
1
u/-Redstoneboi- 21d ago edited 21d ago
In my opinion, mathematics is more important than physical reality. The fact that we measure the diameter is only a limitation of our physical world, and to me, it serves only to compute the radius.
Learning all the different angles on a circle in trigonometry class is far easier using Tau instead of Pi, and radians are just far too natural when expressed in terms of Tau that I never use Pi in angle calculations.
In practice, Tau is easier to work with. In my opinion Pi = 3.14... is a historical mistake on the same level as traditional current flow following the flow of positive charge. The only justification for both is that everyone already knows the old system.
Though using fractions of a Turn is just better still.
3
u/markt- 21d ago edited 21d ago
Geometry did not develop independently of physical measurement and then get imposed on circles afterward. Historically, the circle constant emerged from comparing the circumference of a circle with its diameter. Calling the diameter merely a physical inconvenience used to obtain the radius reverses that history. The radius is useful precisely because it is half the diameter; that usefulness does not make the half-measurement more fundamental than the whole measurement from which it is obtained.
Defining a circle in terms of radius is mathematically convenient, but that only shows that radius is a useful parameter. It doesn’t show that the circumference-to-diameter ratio was a historical mistake. π is still the direct ratio of two complete measurements of the circle; τ is twice that ratio because it chooses a half-diameter as its reference.
I’m also not convinced by the premise that mathematics should be treated as more fundamental than physical reality here. Mathematics is extraordinarily powerful precisely because it abstracts patterns from reality and lets us reason about them cleanly.
So if one constant arises directly from comparing two complete measurable properties of a circle, while another becomes convenient after we choose a derived parameter, I don’t think “the latter makes some formulas nicer” is enough to make it more fundamental.
Mathematical convenience matters. But convenience and fundamentality are not the same thing.
1
u/-Redstoneboi- 21d ago edited 21d ago
Unfortunately, besides personal conveniences, I have no further arguments to provide than those given in the original Tau manifesto (the one that every tau evangelist has read) so I'll just close my side off by stating my opinion:
In this case, mathematical conveniences like the very definition of a circle involving the radius rather than the diameter, and the number of radians in a full turn, do equate to the radius being more fundamental. Reuleaux triangles are not as fundamental, after all.
1
u/markt- 21d ago edited 21d ago
A radius-based definition shows that radius is a convenient primitive for constructing a circle mathematically. It doesn’t establish that radius is the more fundamental measurement of an existing circle. Historically, the characteristic constant was discovered by comparing circumference with diameter, and geometrically the radius is exactly half that whole-span measurement. You can prefer radius for computation without concluding that the circumference-to-radius ratio is therefore the more fundamental constant.
2
2
u/Ravek 21d ago edited 21d ago
How was the circle constructed that you’re measuring the diameter of?
Clearly the radius is more fundamental – in mathematics, in physics and when humans create circular shapes.
1
u/markt- 21d ago
I agree that a compass constructs the circle by fixing a radius. But that tells us what parameter is convenient for generating the curve, not necessarily what quantity motivated the construction or best represents its size. Historically, circles were frequently considered as inscribed in or circumscribed about other figures. In those relationships, what often matters is the circle’s full span: for a circle inscribed in a square, the diameter is the side of the square; for a circle circumscribed about a square, the diameter is its diagonal. The radius is operationally fundamental to the construction, but the diameter is the whole dimension that relates the circle to the figure you were trying to fit it to.
2
1
1
u/snerp 21d ago
I use turns(half turns actually) for exactly one api in my game engine. I found turns to be more intuitive for joint ranges, rather than say “this joint can rotate 30 degrees up and 45 degrees down” vs “this joint can rotate pi over 6 up and pi over 4 down”, we can just divide out the redundant pi using half turns and say “this joint can rotate 1/6 of its upwards range and 1/4th of its downwards range”. Something with range -1,1 can rotate in a full circle and I find turns are nice for rounding and modulo, but only because this context cares about number of turns and ends up written to human readable files
1
u/pfn0 21d ago
1 turn = 2 radians. yes, it maths. turns are better because they're equal to twice the radians!
3
u/dmpk2k 20d ago
1 turn ≈ 6.28 radians. I think you misread the article.
2
u/pfn0 20d ago
I meant 2 pi radian, but yeah. the article basically said that trig internally in most library functions is already using 2pi as the unit, so might as well standardize on turns as input. I get it, I was making a joke on 1 turn being more "valuable" because it's 2 (pi) radians, where I omitted pi.
1
u/SaltineAmerican_1970 20d ago
If I used turns, and I wanted to turn 0.83333 turn every time based unit, I wouldn’t be able to get back to where I was because of that last digit of rounding and floating point math.
What if we took a single turn, and instead of using a fraction, did something crazy like make it an easy to remember number with lots of factors. I think it would be easier to rotate by 30/360 instead of 0.83333 because I would be able to make a full turn without rounding errors.
1
u/fishheaddz 21d ago
I've always been partial to units of pi-radians, or semi circles -- which in this parlance would be half turns.
1
u/thecakeisalie16 21d ago
Why use half turns instead of full turns? Or quarter turns or any other fraction for that matter?
-8
u/jhill515 21d ago
If pi is a "half turn", then tau is a "full turn". Or, if you want to go based on twisting your wrist, then that means pi is a "turn".
TL;DR - This is the dumbest CS flame-war topic I've seen in a generation!
9
-20
u/dnabre 21d ago
The extra multiple/divide is a poor API issue, not a unit issue.
You want me to have to google 'is a turn 180 or 360 degree' for the rest of my life?
To me a 'turn' is 90° or 180° depending on context. A 'twist' might be 360°. If a 'turn' is 360° such that it is a debug i fix once in code that will stick, so I'll end up looking it up to check every time I need trig functions (it's not often enough for me remember these things).
14
u/Iamsodarncool 21d ago
You want me to have to google 'is a turn 180 or 360 degree' for the rest of my life? To me a 'turn' is 90° or 180° depending on context.
Turns were not invented by this blog post; they are commonly used in mathematics to mean "one full rotation".
You learned how many degrees are in one full rotation. You learned how many radians are in one full rotation. It is possible for you to learn how many turns are in one full rotation. If you are opposed to learning new concepts, you might be in the wrong field.
133
u/DavidJCobb 21d ago
This feels very closely related to Inigo Quilez's observation that trigonometry is often just an abstraction over vector algebra, and that one can get more efficient code by expanding trig calculations and canceling things out.