This is an API proposal for adding Tau
to System.Math
and System.MathF
. These values would be exactly equal to 2 times Math.PI
and 2 times MathF.PI
respectively, and would represent a full rotation around the unit circle in radians.
The System.Math
class currently has PI
, but there is one other circle constant that is quite common and useful that is missing: Tau (Ï„
), which is 2Ï€
, or about 6.283185307179586476925
.
Tau represents a rotation all the way around the circle, in radians. As demonstrated in the Tau manifesto, this value is extremely common throughout numerous mathematical functions.
In my own experience writing code that works with angles and rotations, I have found that using Tau results in much cleaner code. Some examples:
If you need to write down a rotation in your code, it is much easier to understand when expressed in terms of Tau.
It is immediately clear that double rotation = Math.Tau / 3;
is a rotation one third of the way around the unit circle in radians, and double rotation = Math.Tau * 0.6;
is a rotation 60% of the way around the unit circle in radians.
Using Pi, those values would have to be written as Math.PI * 2 / 3
and Math.PI * 1.2
(or * 2 * 0.6
) respectively, which is much less clear.
Here's an image pulled from the Tau manifesto to illustrate the point:
If you have rotation represented as a ratio (0 to 1) of how far it is around the unit circle, then you can multiply that ratio by Tau to get a rotation around the unit circle of radians.
delta
which represents the time passed since last frame, code like rotation += delta * Math.Tau;
will rotate once per second. This can then simply be multiplied with the desired rate per second. Without Math.Tau
, you would need to multiply by 2, adding complexity and confusion.If you are accepting input as a rotation and need to normalize the input, you could use value % Math.Tau
to normalize the input. With Pi, you would need to write value % Math.PI * 2
While I'm not an expert on audio, just from a search in Godot's source code, it seems that code working with audio waveforms deals with Tau (or 2*Pi) very frequently as well.
Tau is used commonly in the Godot game engine.
Obviously I could just create my own helper class for this, but it would be better if it was implemented in .NET and C#, available for all users of .NET and C#.
Not everyone would use it, and that's fine, but I think it is best if .NET and C# encourage writing cleaner code by allowing developers to use Tau
in addition to PI
"out of the box".
The following line would be added to System.Math
:
public const double Tau = 6.283185307179586476925;
The following line would be added to System.MathF
:
public const float Tau = 6.283185307f;
If you need more details, consider reading through the Tau manifesto.
The name TwoPi
has also been suggested. It should be considered, but I think Tau
is a better choice. The name Tau
has been popularized by articles such as the Tau manifesto. The Greek letter Ï„
(tau) resembles a T, which can stand for "turn", and it is visually similar to the Greek letter π
(pi).
None so far.
https://github.com/dotnet/runtime/issues/24678#issuecomment-639654359
Only Math.Pi
and Math.E
are exposed constants. The others are special test inputs/outputs (only defined in the unit test library) that are used to validate the math functions return the way expected value for some "well-know" values.
Why not have more exposed constants? They are useful, after all.
Are they? Let me turn that around and ask, why? Is it super common to maintain your own tau and half-pi constants, such that this would lift a burden from people? That's new to me.
The fact that you seem to not be recognizing xkcd’s ‘pau’ as a joke raises a red flag in my mind.
I don't have any specific preference for or against exposing them. There are some libm implementations that expose similar constants, but they also haven't been exposed as part of the "public surface area" in the actual C/C++ standards.
They do represent core values that various math libraries may need to consume/produce; However, they are also just constants with well-defined values, so it isn't difficult for any particular library to define (and has no impact on the IL generated outside of having a member you can discover via reflection).
I do know it's a joke, but it's still a simple name to use. Would you rather call the variable Math.THREEHALVESPI
or Math.THREEQUARTERSTAU
?
If they're simple to define in any library, why not define them in this library?
If they're simple to define in any library, why not define them in this library?
@aaronfranke, if you do want to "officially" propose CoreFX add the APIs, you should follow the steps here and submit a "formal" API proposal (probably by just updating the OP, rather than opening a new issue).
How common are these constants? How often are they used by System.Math users?
The names should be something everyone recognizes (discoverability), otherwise their value goes significantly down.
why not define them in this library
We don't add every API we can, but only APIs, which are useful for a wider developer audience and are truly used / useful in real-world scenarios. Otherwise we would drown in lots of marginal APIs - making it harder for developers to choose which APIs to use. Everything comes at a cost - general API surface ease-of-use in this case.
How common are these constants?
Tau is not very commonly used, but it has its advocates (though the symbol has also been used for ½π and for the golden ratio instead of φ). Pau was invented by Randal Munroe to make fun of people who argue about whether or not we should use Tau.
@karelz, they are fairly core mathematical constants that are used in multiple places (we use many of them for validating correctness in our Math APIs, and I've seen a few scattered about in both managed and native land for CoreFX/CoreCLR). They are generally defined to account for minor inaccuracies in the floating-point format (e.g. 2 * Math.PI
may be slightly different than Math.TwoPi
)
However, as indicated above, since these are well-defined constants, it is also trivial to add them to your own code base (but equally as trivial to add them to CoreFX).
LibM defines the following: https://www.gnu.org/software/libc/manual/html_node/Mathematical-Constants.html#Mathematical-Constants. If we were to add any constants, I would think they should be these
I would also vote we use names like TwoPi
, rather than Tau
.
In theory, TwoPi and HalfPi have the exact same precision as PI but the exponent is incremented or decremented, right? Things like M_1_PI make a lot more sense to me.
In theory, TwoPi and HalfPi have the exact same precision as PI but the exponent is incremented or decremented, right?
Basically, yes.
```C#
const double pi_d = 3.1415926535897932; // 0x400921FB54442D18
const double two_pi_d = 6.2831853071795865; // 0x401921FB54442D18
const double half_pi_d = 1.5707963267948966; // 0x3FF921FB54442D18
const float pi_f = 3.14159265f; // 0x40490FDB
const float two_pi_f = 6.28318531f; // 0x40C90FDB
const float half_pi_f = 1.57079633f; // 0x3FC90FDB
```
And, for the default rounding mode, Math.PI * 2
is exactly the same as Math.TwoPi
. But it may not always be exactly the same in all rounding modes and other more complex constants may differ.
In default rounding mode, how is it possible for the most precise representations of ComplexConstant
and 2 * ComplexConstant
not to have the exact same mantissa no matter how complex the constant is?
In default rounding mode, how is it possible for the most precise representations of ComplexConstant and 2 * ComplexConstant not to have the exact same mantissa no matter how complex the constant is?
Denormal numbers, where the exponent is zero 😄
Oh, gotcha. But we aren't talking about adding constants that small, right?
Oh, gotcha. But we aren't talking about adding constants that small, right?
No. But there are other multipliers (1.5 * PI
) and more complex constants (Log2(E)
) whose "exact" result may differ from the result returned by computing it in managed code (I haven't actually gone and checked which).
Yes. I would expect actual multiplication to cause that. Though in the particular case of 0.75*pi, I'm getting 0x4002D97C7F3321D2 no matter how I calculate it as well as when letting the compiler pick the representation given a literal with more than enough digits. (That makes particular sense to me because the only prime factor in the divisor is two, so we're only doing integer multiplication in the mantissa.) So the only advantage in adding any of these eighths increments of a circle would have to be as Karel said– they have to be of routine interest to people looking through the API.
There are numerous constants available in math.h / cmath.h... https://msdn.microsoft.com/en-us/library/4hwaceh6.aspx when you define _USE_MATH_DEFINES for c/c++. Seems like it'd be pretty simple to include these in the .Net System.Math and they are obviously useful.
This issue hasn't seen activity in over a year. Is there demand for this API? If not, we should probably close the issue if we're not still collecting information on whether these would be useful in the public surface area.
There really isn't much to discuss, it's a simple feature.
I use Tau
all the time, but I usually use C# in the context of Godot, which has its own Mathf
static class, so Tau
in System.Math
is not a dire need or anything but it would be greatly appreciated for any time I'm using C# outside of Godot.
There is demand from me. I usually use Tau
in place of Pi
when working with rotations. Side note, perhaps Math.PI
should be Math.Pi
to match C#'s naming system.
I'm against exposing Tau
as constant in System.Math
as tau can have several meanings (also with regards to different cultures, i.e. Europe and US), depending on the context.
The same is somewhat true for pi, but there it is quite obvious that 3.141592... is meant.
Furthermore it's quite easy to expose "derived" constants via const
or static readonly
(which the JIT will treat as constants after static initialization is done, especially for Tier-1).
So let's keep it simple and clear.
@aaronfranke, I'll take this to API review if you could update the original post to follow the "good example" listed under step 1 of our [API Review Process](https://github.com/dotnet/runtime/blob/master/docs/project/api-review-process.md. You don't strictly speaking need all the sections, but providing the rationale/usage and proposed API sections would be ideal as it helps the API review process overall.
For Tau
in particular, I'm fine with taking it to API review as Tau
, but the other possible names (such as TwoPi
) will likely get brought up as well.
If possible, it would be great if you could also list some of the other common math constants as part of the proposal, so they can all be reviewed at once (I believe https://www.gnu.org/software/libc/manual/html_node/Mathematical-Constants.html lists the most common ones, but there may be others).
Any constants proposed for System.Math
should likewise be proposed for System.MathF
.
@tannergooding Thanks, I've went ahead and done that (using my Color proposal as a reference).
@tannergooding Interestingly, the CRT math constants you linked to define all kind of other variants, but not the specific value 2Ï€. :)
@GrabYourPitchforks, ah you're right, from the corecrt_math_defines.h
file with MSVC:
// Definitions of useful mathematical constants
//
// Define _USE_MATH_DEFINES before including <math.h> to expose these macro
// definitions for common math constants. These are placed under an #ifdef
// since these commonly-defined names are not part of the C or C++ standards
#define M_E 2.71828182845904523536 // e
#define M_LOG2E 1.44269504088896340736 // log2(e)
#define M_LOG10E 0.434294481903251827651 // log10(e)
#define M_LN2 0.693147180559945309417 // ln(2)
#define M_LN10 2.30258509299404568402 // ln(10)
#define M_PI 3.14159265358979323846 // pi
#define M_PI_2 1.57079632679489661923 // pi/2
#define M_PI_4 0.785398163397448309616 // pi/4
#define M_1_PI 0.318309886183790671538 // 1/pi
#define M_2_PI 0.636619772367581343076 // 2/pi
#define M_2_SQRTPI 1.12837916709551257390 // 2/sqrt(pi)
#define M_SQRT2 1.41421356237309504880 // sqrt(2)
#define M_SQRT1_2 0.707106781186547524401 // 1/sqrt(2)
@tannergooding It sounds like we also have the opportunity to introduce this constant with the Tau
name into MSVC/GCC/etc, though that's a separate discussion for another time and repo :)
Approved as Tau:
C#
public partial class Math
{
public const double Tau = 6.283185307179586476925;
}
public partial class MathF
{
public const float Tau = 6.283185307f;
}
Can I take this?
Assigned out, thanks @john-h-k!
Most helpful comment
Approved as Tau:
C# public partial class Math { public const double Tau = 6.283185307179586476925; } public partial class MathF { public const float Tau = 6.283185307f; }