Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Proposal: Add Tau to System.Math(F) class #24678

Closed
aaronfranke opened this issue Jan 15, 2018 · 30 comments · Fixed by #37517
Closed

API Proposal: Add Tau to System.Math(F) class #24678

aaronfranke opened this issue Jan 15, 2018 · 30 comments · Fixed by #37517
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-System.Numerics
Milestone

Comments

@aaronfranke
Copy link

aaronfranke commented Jan 15, 2018

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.

Rationale and usage

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 , 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.

    • If you have code that works iteratively, and you have a variable called 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

    • Note that if you need to handle negative values, you would also need a helper method.
  • 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".

Proposed API

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;

Details

If you need more details, consider reading through the Tau manifesto.

Open Questions

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).

Pull Request

None so far.

Updates

#24678 (comment)

@tannergooding
Copy link
Member

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.

@aaronfranke
Copy link
Author

Why not have more exposed constants? They are useful, after all.

@jnm2
Copy link
Contributor

jnm2 commented Jan 16, 2018

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.

@tannergooding
Copy link
Member

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).

@aaronfranke
Copy link
Author

aaronfranke commented Jan 16, 2018

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?

@tannergooding
Copy link
Member

If they're simple to define in any library, why not define them in this library?

  1. I don't think anyone has proposed it yet.
  2. There are many more (IMO) useful APIs to add to CoreFX, that provide significant benefit and that are not trivial to implement (this includes APIs in the System.Math library)

@tannergooding
Copy link
Member

@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).

@karelz
Copy link
Member

karelz commented Jan 16, 2018

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.

@JonHanna
Copy link
Contributor

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.

@tannergooding
Copy link
Member

@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.

@jnm2
Copy link
Contributor

jnm2 commented Jan 16, 2018

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.

@tannergooding
Copy link
Member

In theory, TwoPi and HalfPi have the exact same precision as PI but the exponent is incremented or decremented, right?

Basically, yes.

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

@tannergooding
Copy link
Member

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.

@jnm2
Copy link
Contributor

jnm2 commented Jan 16, 2018

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?

@tannergooding
Copy link
Member

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 😄

@jnm2
Copy link
Contributor

jnm2 commented Jan 16, 2018

Oh, gotcha. But we aren't talking about adding constants that small, right?

@tannergooding
Copy link
Member

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).

@jnm2
Copy link
Contributor

jnm2 commented Jan 16, 2018

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.

@aaronfranke aaronfranke changed the title Add Tau and Pau to System.Math class Add Tau to System.Math class Apr 23, 2018
@CodeBendor
Copy link

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.

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 5.0 milestone Jan 31, 2020
@GrabYourPitchforks
Copy link
Member

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.

@aaronfranke
Copy link
Author

aaronfranke commented Feb 11, 2020

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.

@gfoidl
Copy link
Member

gfoidl commented Feb 11, 2020

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.

@tannergooding
Copy link
Member

@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.

@aaronfranke aaronfranke changed the title Add Tau to System.Math class API Proposal: Add Tau to System.Math class Mar 4, 2020
@aaronfranke
Copy link
Author

@tannergooding Thanks, I've went ahead and done that (using my Color proposal as a reference).

@aaronfranke aaronfranke changed the title API Proposal: Add Tau to System.Math class API Proposal: Add Tau to System.Math(F) class Mar 4, 2020
@tannergooding tannergooding removed the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Mar 4, 2020
@GrabYourPitchforks
Copy link
Member

@tannergooding Interestingly, the CRT math constants you linked to define all kind of other variants, but not the specific value 2π. :)

@tannergooding
Copy link
Member

@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)

@aaronfranke
Copy link
Author

@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 :)

@bartonjs
Copy link
Member

bartonjs commented Jun 5, 2020

Approved as Tau:

public partial class Math
{
    public const double Tau = 6.283185307179586476925;
}
public partial class MathF
{
    public const float Tau = 6.283185307f;
}

@bartonjs bartonjs added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review labels Jun 5, 2020
@john-h-k
Copy link
Contributor

john-h-k commented Jun 5, 2020

Can I take this?

@tannergooding
Copy link
Member

Assigned out, thanks @john-h-k!

@ghost ghost locked as resolved and limited conversation to collaborators Dec 18, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Numerics
Projects
None yet
Development

Successfully merging a pull request may close this issue.