## digitalmars.D - support for various angular units in std.math

- Colin Wallace <wallacoloo gmail.com> Feb 27 2011
- "Simen kjaeraas" <simen.kjaras gmail.com> Feb 27 2011
- Walter Bright <newshound2 digitalmars.com> Feb 27 2011
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Feb 28 2011
- bearophile <bearophileHUGS lycos.com> Feb 28 2011
- KB <nospam spam.com> Feb 28 2011
- Peter Alexander <peter.alexander.au gmail.com> Feb 28 2011
- Trass3r <un known.com> Feb 28 2011
- Peter Alexander <peter.alexander.au gmail.com> Feb 28 2011
- Don <nospam nospam.com> Feb 28 2011
- Colin Wallace <wallacoloo gmail.com> Feb 28 2011
- Don <nospam nospam.com> Mar 01 2011

I've been doing a lot of opengl work in D. Opengl deals primarily (maybe even completely?) with degrees. When using trigonometric functions, they all deal with radians. So I've been having to do lots of converting. Converting is very straightforward, but I still think it would be nice if there were some built in functions for dealing with other units than radians. I think a system that looked like what is used for the Duration struct in core.time would make things more readable. The code for taking the sine of a number measured in degrees could look like: sin!"degrees"(45) rather than sin(45*PI/180) It doesn't make a huge difference to me, but neither does the dur!() function, yet somebody decided it would be helpful and it made its way into the standard library. So I figured I would at least share this idea to see what other people thought of it.

Feb 27 2011

Colin Wallace <wallacoloo gmail.com> wrote:I've been doing a lot of opengl work in D. Opengl deals primarily (maybe even completely?) with degrees. When using trigonometric functions, they all deal with radians. So I've been having to do lots of converting. Converting is very straightforward, but I still think it would be nice if there were some built in functions for dealing with other units than radians. I think a system that looked like what is used for the Duration struct in core.time would make things more readable. The code for taking the sine of a number measured in degrees could look like: sin!"degrees"(45) rather than sin(45*PI/180) It doesn't make a huge difference to me, but neither does the dur!() function, yet somebody decided it would be helpful and it made its way into the standard library. So I figured I would at least share this idea to see what other people thought of it.

I think a better solution would be a proper units struct: unit!"degrees" a; sin(a); // Automagically behaves correctly bool foo(unit!"radians" bar) { return bar < PI; } foo(a); // Compile-time error: degrees not equal to radians. -- Simen

Feb 27 2011

Colin Wallace wrote:When using trigonometric functions, they all deal with radians. So I've been having to do lots of converting. Converting is very straightforward, but I still think it would be nice if there were some built in functions for dealing with other units than radians. I think a system that looked like what is used for the Duration struct in core.time would make things more readable. The code for taking the sine of a number measured in degrees could look like: sin!"degrees"(45) rather than sin(45*PI/180)

I appreciate the suggestion, but suspect that adding a parallel set of trig functions that do nothing more than multiply the arg by a constant is more cognitive load for the user than benefit.

Feb 27 2011

On 2/28/11 12:49 AM, Walter Bright wrote:Colin Wallace wrote:When using trigonometric functions, they all deal with radians. So I've been having to do lots of converting. Converting is very straightforward, but I still think it would be nice if there were some built in functions for dealing with other units than radians. I think a system that looked like what is used for the Duration struct in core.time would make things more readable. The code for taking the sine of a number measured in degrees could look like: sin!"degrees"(45) rather than sin(45*PI/180)

I appreciate the suggestion, but suspect that adding a parallel set of trig functions that do nothing more than multiply the arg by a constant is more cognitive load for the user than benefit.

Agreed. What would add value is a units library that refuses calls to e.g. trig functions unless the user specifically inserts a conversion. That is, instead of sin!"degrees"(x); you'd use: sin(to!"degrees"(x)); That way the conversion remains explicit but is hoisted out of the multitude of math functions. Andrei

Feb 28 2011

Andrei:you'd use: sin(to!"degrees"(x)); That way the conversion remains explicit but is hoisted out of the multitude of math functions.

Have you seen Don's answer? http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=130757 Bye, bearophile

Feb 28 2011

For a very tidy and typesafe implementation of units I would recommend checking out the units feature in F#. http://blogs.msdn.com/b/andrewkennedy/archive/2008/08/29/units-of-measure-in-f-part-one-introducing-units.aspx Probably not the best link, but the compiler will flag if units are not consistent in computations. Also accept they adopt a 'tagging' system to declare units, but conversely it is very extensable to any set of defined units. K

Feb 28 2011

On 28/02/11 1:17 AM, Colin Wallace wrote:I've been doing a lot of opengl work in D. Opengl deals primarily (maybe even completely?) with degrees. When using trigonometric functions, they all deal with radians. So I've been having to do lots of converting. Converting is very straightforward, but I still think it would be nice if there were some built in functions for dealing with other units than radians. I think a system that looked like what is used for the Duration struct in core.time would make things more readable. The code for taking the sine of a number measured in degrees could look like: sin!"degrees"(45) rather than sin(45*PI/180) It doesn't make a huge difference to me, but neither does the dur!() function, yet somebody decided it would be helpful and it made its way into the standard library. So I figured I would at least share this idea to see what other people thought of it.

When you start doing OpenGL properly, degrees don't show up at all. In fact, I believe all degrees functions are deprecated in the latest version (could be wrong on this). Really, you should be doing all the matrix calculations and rotations yourself. If anything should come out of this, it would be a nice, small linear algebra library.

Feb 28 2011

Really, you should be doing all the matrix calculations and rotations yourself. If anything should come out of this, it would be a nice, small linear algebra library.

I think you even have to do that in OpenGL 4 (maybe even 3).

Feb 28 2011

On 28/02/11 10:12 AM, Trass3r wrote:Really, you should be doing all the matrix calculations and rotations yourself. If anything should come out of this, it would be a nice, small linear algebra library.

I think you even have to do that in OpenGL 4 (maybe even 3).

Yep, I'm pretty sure you're right.

Feb 28 2011

Colin Wallace wrote:I've been doing a lot of opengl work in D. Opengl deals primarily (maybe even completely?) with degrees. When using trigonometric functions, they all deal with radians. So I've been having to do lots of converting. Converting is very straightforward,

Actually, it isn't! assert(sin(360 * PI / 180 ) == 0.0); // fails! There are supposed to be sinPi(), cosPi(), tanPi() functions, but they are not yet implemented (they are quite difficult to get right). You should use: sinPi(360/180); to get sine in degrees.

Feb 28 2011

Don Wrote:Colin Wallace wrote:When using trigonometric functions, they all deal with radians. So I've been having to do lots of converting. Converting is very straightforward,

Actually, it isn't! assert(sin(360 * PI / 180 ) == 0.0); // fails!

That's a very marginal error (1e-19). For graphics, I never need that much precision. Besides, it has nothing to do with the conversion in this case. sin(2*PI) results in the same value, causing the assertion to fail.

Feb 28 2011

Colin Wallace wrote:Don Wrote:Colin Wallace wrote:When using trigonometric functions, they all deal with radians. So I've been having to do lots of converting. Converting is very straightforward,

assert(sin(360 * PI / 180 ) == 0.0); // fails!

That's a very marginal error (1e-19). For graphics, I never need that much precision.

Yes, but someone doing high school trigonometry with degrees will be confused when it fails.Besides, it has nothing to do with the conversion in this case. sin(2*PI) results in the same value, causing the assertion to fail.

No, it's the conversion. It's because the mathematical number pi is not precisely representable in floating point. But 360 is precisely representable, and sin(360 degrees) is also precisely representable. assert(sinPi(360/180) == 0) will pass. So multiplying by PI is *not* the correct way to calculate trignometric functions in degrees. 2*PI is not 360 degrees.

Mar 01 2011