www.digitalmars.com         C & C++   DMDScript  

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

reply Colin Wallace <wallacoloo gmail.com> writes:
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
next sibling parent "Simen kjaeraas" <simen.kjaras gmail.com> writes:
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
prev sibling next sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
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
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
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
parent reply bearophile <bearophileHUGS lycos.com> writes:
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
parent KB <nospam spam.com> writes:
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
prev sibling next sibling parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
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
parent reply Trass3r <un known.com> writes:
 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
parent Peter Alexander <peter.alexander.au gmail.com> writes:
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
prev sibling parent reply Don <nospam nospam.com> writes:
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
parent reply Colin Wallace <wallacoloo gmail.com> writes:
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
parent Don <nospam nospam.com> writes:
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