## digitalmars.D - std.math2 proposal

- "Ben Hinkle" <bhinkle mathworks.com> Aug 18 2005
- "Charles" <noone nowhere.com> Aug 18 2005
- "Ben Hinkle" <ben.hinkle gmail.com> Aug 18 2005
- Don Clugston <dac nospam.com.au> Aug 18 2005
- "Ben Hinkle" <ben.hinkle gmail.com> Aug 18 2005
- Burton Radons <burton-radons smocky.com> Aug 18 2005
- "Ben Hinkle" <ben.hinkle gmail.com> Aug 18 2005
- Don Clugston <dac nospam.com.au> Aug 18 2005
- "Ben Hinkle" <ben.hinkle gmail.com> Aug 19 2005
- Dave <Dave_member pathlink.com> Aug 19 2005
- "Ben Hinkle" <bhinkle mathworks.com> Aug 19 2005
- Don Clugston <dac nospam.com.au> Aug 21 2005
- "Ben Hinkle" <bhinkle mathworks.com> Aug 22 2005
- Burton Radons <burton-radons smocky.com> Aug 22 2005
- "Ben Hinkle" <bhinkle mathworks.com> Aug 22 2005
- Burton Radons <burton-radons smocky.com> Aug 23 2005
- "Walter" <newshound digitalmars.com> Aug 21 2005
- Don Clugston <dac nospam.com.au> Aug 21 2005

Right now in std.math2 there are several "min" and "max" and various other high-level math overloads. For example min(int x, int y), min(long x, long y), min(real x, real y), min(int[] x), min(long[] x), min(real[] x). I'd like to replace those with template min(T:T[]) { T min(T[] x) { T res = T.max; foreach(T val; x) { if (val < res) res = val; } return res; } } template min(T) { T min(T[] x ...) { return min!(T[])(x); } } User code would look like, for example, min!(int)(10, 20) min!(short)(x, 10) max!(double)(10, 33.33, -PI, 2*PI, 0); int[] nums = ...; int bound = max!(int[])(nums); With inlining the simple calls with just two elements should be just as fast as exising solutions. I could also see using templates for sum, too, and maybe even sqr, sign and abs. I suppose documenting std.math2 would also be worthwhile. Then again putting some of the more useful definitions in std.math and leaving std.math2 be is another option. I don't know what the original design of math/math2 was for. Thoughts?

Aug 18 2005

Sounds good to me , I use my own handrolled templates for these already , as a part of phobos would be much better ... and math2 isn't document or even mentioned in the official docs , be nice to have a refrence for it. Not sure why math2 even exists, why not throw them all in math ? Charlie "Ben Hinkle" <bhinkle mathworks.com> wrote in message news:de2hb4$1pf$1 digitaldaemon.com...Right now in std.math2 there are several "min" and "max" and various other high-level math overloads. For example min(int x, int y), min(long x, long y), min(real x, real y), min(int[] x), min(long[] x), min(real[] x). I'd like to replace those with template min(T:T[]) { T min(T[] x) { T res = T.max; foreach(T val; x) { if (val < res) res = val; } return res; } } template min(T) { T min(T[] x ...) { return min!(T[])(x); } } User code would look like, for example, min!(int)(10, 20) min!(short)(x, 10) max!(double)(10, 33.33, -PI, 2*PI, 0); int[] nums = ...; int bound = max!(int[])(nums); With inlining the simple calls with just two elements should be just as

as exising solutions. I could also see using templates for sum, too, and maybe even sqr, sign

abs. I suppose documenting std.math2 would also be worthwhile. Then again putting some of the more useful definitions in std.math and leaving std.math2 be is another option. I don't know what the original design of math/math2 was for. Thoughts?

Aug 18 2005

"Charles" <noone nowhere.com> wrote in message news:de3034$fhe$1 digitaldaemon.com...Sounds good to me , I use my own handrolled templates for these already , as a part of phobos would be much better ... and math2 isn't document or even mentioned in the official docs , be nice to have a refrence for it. Not sure why math2 even exists, why not throw them all in math ?

Yeah, I'm thinking that would make sense, too. Here's the contents of math2 for those who haven't opened it lately. A couple of ideas come to mind: 1) deprecate feq now that we have feqrel 2) deprecate toString and atof since they are in std.string 3) deprecate conversions between angle units 4) move everything else to std.math with templates for the overloaded functions bit feq(real a, real b) bit feq(real a, real b, real eps) int abs(int n) long abs(long n) real abs(real n) int sqr(int n) long sqr(long n) real sqr(real n) real trunc(real n) real frac(real n) real poly(real x, real[] coefficients) int sign(int n) int sign(long n) int sign(real n) real cycle2deg(real c) real cycle2rad(real c) real cycle2grad(real c) real deg2cycle(real d) real deg2rad(real d) real deg2grad(real d) real rad2deg(real r) real rad2cycle(real r) real rad2grad(real r) real grad2deg(real g) real grad2cycle(real g) real grad2rad(real g) real avg(real[] n) int sum(int[] n) long sum(long[] n) real sum(real[] n) int min(int[] n) long min(long[] n) real min(real[] n) int min(int a, int b) long min(long a, long b) real min(real a, real b) int max(int[] n) long max(long[] n) real max(real[] n) int max(int a, int b) long max(long a, long b) real max(real a, real b) real acot(real x) real asec(real x) real acosec(real x) real cot(real x) real sec(real x) real cosec(real x) real coth(real x) real sech(real x) real cosech(real x) real acosh(real x) real asinh(real x) real atanh(real x) real acoth(real x) real asech(real x) real acosech(real x) real atof(char[] s) char[] toString(real x)

Aug 18 2005

I agree. The date in math2 is 2002 -- things have changed a lot since then. Some of that stuff is a bit bizarre -- who uses grads???? abs() is the most important thing in there, but why isn't it an intrinsic? A compiler can do tricks like: // eliminates a poorly predictable branch int fastAbs(int x) { asm { mov EAX, [x]; cdq; xor EAX, EDX; sub EAX, EDX; } } (not generally applicable because it only works for EAX, EDX, won't optimise well in general). I could imagine a processor including abs in its instruction set. But as a minimum it should be in std.math. A comment about your templates for max,min: with sum and avg, when using floats/doubles, you should be accumulating in a real. Likewise ints should accumulate in a long. Might be nice to also have a template for these cases which returned 'long' for integral types, 'real' for floats, ireal for imaginary, creal for complex, and passed user defined types straight through. [[ ... except, if your type was (say) MyPolyType!(double), you might want to upgrade it to a MyPolyType!(real) ... nice idea, but probably never required. ]] Does sqr() deserve to be in there? It doesn't add any value that I can see. Also I'm not sure that sign() is useful since we have signbit() in std.math -- when would you use it? Likewise, all the auxilliary trig funcs (cot, sec, cosec, coth,..) can be trivially generated from the standard ones. I think that unless there's some accuracy subtleties or a speed advantage, it's hard to justify something so simple. Especially since the use of asm in that case probably _inhibits_ optimisation! eg 2.5 * cot(x) should become 2.5/tan(x). -Don. Ben Hinkle wrote:"Charles" <noone nowhere.com> wrote in message news:de3034$fhe$1 digitaldaemon.com...Sounds good to me , I use my own handrolled templates for these already , as a part of phobos would be much better ... and math2 isn't document or even mentioned in the official docs , be nice to have a refrence for it. Not sure why math2 even exists, why not throw them all in math ?

Yeah, I'm thinking that would make sense, too. Here's the contents of math2 for those who haven't opened it lately. A couple of ideas come to mind: 1) deprecate feq now that we have feqrel 2) deprecate toString and atof since they are in std.string 3) deprecate conversions between angle units 4) move everything else to std.math with templates for the overloaded functions bit feq(real a, real b) bit feq(real a, real b, real eps) int abs(int n) long abs(long n) real abs(real n) int sqr(int n) long sqr(long n) real sqr(real n) real trunc(real n) real frac(real n) real poly(real x, real[] coefficients) int sign(int n) int sign(long n) int sign(real n) real cycle2deg(real c) real cycle2rad(real c) real cycle2grad(real c) real deg2cycle(real d) real deg2rad(real d) real deg2grad(real d) real rad2deg(real r) real rad2cycle(real r) real rad2grad(real r) real grad2deg(real g) real grad2cycle(real g) real grad2rad(real g) real avg(real[] n) int sum(int[] n) long sum(long[] n) real sum(real[] n) int min(int[] n) long min(long[] n) real min(real[] n) int min(int a, int b) long min(long a, long b) real min(real a, real b) int max(int[] n) long max(long[] n) real max(real[] n) int max(int a, int b) long max(long a, long b) real max(real a, real b) real acot(real x) real asec(real x) real acosec(real x) real cot(real x) real sec(real x) real cosec(real x) real coth(real x) real sech(real x) real cosech(real x) real acosh(real x) real asinh(real x) real atanh(real x) real acoth(real x) real asech(real x) real acosech(real x) real atof(char[] s) char[] toString(real x)

Aug 18 2005

"Don Clugston" <dac nospam.com.au> wrote in message news:de387d$msf$1 digitaldaemon.com...I agree. The date in math2 is 2002 -- things have changed a lot since then. Some of that stuff is a bit bizarre -- who uses grads???? abs() is the most important thing in there, but why isn't it an intrinsic? A compiler can do tricks like: // eliminates a poorly predictable branch int fastAbs(int x) { asm { mov EAX, [x]; cdq; xor EAX, EDX; sub EAX, EDX; } } (not generally applicable because it only works for EAX, EDX, won't optimise well in general). I could imagine a processor including abs in its instruction set. But as a minimum it should be in std.math.

okA comment about your templates for max,min: with sum and avg, when using floats/doubles, you should be accumulating in a real. Likewise ints should accumulate in a long. Might be nice to also have a template for these cases which returned 'long' for integral types, 'real' for floats, ireal for imaginary, creal for complex, and passed user defined types straight through.

Good point. I was actually thinking avg would stay as a real-only function since averaging a bunch of ints will probably result in a non-int. Maybe it can support float/double but the rest of std.math deals with reals. How about only min/max work with generic types, sum works with anything and returns long or real and avg only works with real.[[ ... except, if your type was (say) MyPolyType!(double), you might want to upgrade it to a MyPolyType!(real) ... nice idea, but probably never required. ]] Does sqr() deserve to be in there? It doesn't add any value that I can see.

yeah - the only thing I could think of was that expr needs to be written out twice expr*expr instead of once sqr(expr). But that's not worth a whole function, I agree.Also I'm not sure that sign() is useful since we have signbit() in std.math -- when would you use it?

I'm on the fence with that since taking the sign of an int shouldn't have to go through signbit(real). To me this is on the save level as abs().Likewise, all the auxilliary trig funcs (cot, sec, cosec, coth,..) can be trivially generated from the standard ones. I think that unless there's some accuracy subtleties or a speed advantage, it's hard to justify something so simple. Especially since the use of asm in that case probably _inhibits_ optimisation! eg 2.5 * cot(x) should become 2.5/tan(x).

agreed. deprecate.-Don. Ben Hinkle wrote:"Charles" <noone nowhere.com> wrote in message news:de3034$fhe$1 digitaldaemon.com...Sounds good to me , I use my own handrolled templates for these already , as a part of phobos would be much better ... and math2 isn't document or even mentioned in the official docs , be nice to have a refrence for it. Not sure why math2 even exists, why not throw them all in math ?

Yeah, I'm thinking that would make sense, too. Here's the contents of math2 for those who haven't opened it lately. A couple of ideas come to mind: 1) deprecate feq now that we have feqrel 2) deprecate toString and atof since they are in std.string 3) deprecate conversions between angle units 4) move everything else to std.math with templates for the overloaded functions bit feq(real a, real b) bit feq(real a, real b, real eps) int abs(int n) long abs(long n) real abs(real n) int sqr(int n) long sqr(long n) real sqr(real n) real trunc(real n) real frac(real n) real poly(real x, real[] coefficients) int sign(int n) int sign(long n) int sign(real n) real cycle2deg(real c) real cycle2rad(real c) real cycle2grad(real c) real deg2cycle(real d) real deg2rad(real d) real deg2grad(real d) real rad2deg(real r) real rad2cycle(real r) real rad2grad(real r) real grad2deg(real g) real grad2cycle(real g) real grad2rad(real g) real avg(real[] n) int sum(int[] n) long sum(long[] n) real sum(real[] n) int min(int[] n) long min(long[] n) real min(real[] n) int min(int a, int b) long min(long a, long b) real min(real a, real b) int max(int[] n) long max(long[] n) real max(real[] n) int max(int a, int b) long max(long a, long b) real max(real a, real b) real acot(real x) real asec(real x) real acosec(real x) real cot(real x) real sec(real x) real cosec(real x) real coth(real x) real sech(real x) real cosech(real x) real acosh(real x) real asinh(real x) real atanh(real x) real acoth(real x) real asech(real x) real acosech(real x) real atof(char[] s) char[] toString(real x)

Aug 18 2005

Ben Hinkle wrote:"Don Clugston" <dac nospam.com.au> wrote in message news:de387d$msf$1 digitaldaemon.com...I agree. The date in math2 is 2002 -- things have changed a lot since then. Some of that stuff is a bit bizarre -- who uses grads???? abs() is the most important thing in there, but why isn't it an intrinsic? A compiler can do tricks like: // eliminates a poorly predictable branch int fastAbs(int x) { asm { mov EAX, [x]; cdq; xor EAX, EDX; sub EAX, EDX; } } (not generally applicable because it only works for EAX, EDX, won't optimise well in general). I could imagine a processor including abs in its instruction set. But as a minimum it should be in std.math.

okA comment about your templates for max,min: with sum and avg, when using floats/doubles, you should be accumulating in a real. Likewise ints should accumulate in a long. Might be nice to also have a template for these cases which returned 'long' for integral types, 'real' for floats, ireal for imaginary, creal for complex, and passed user defined types straight through.

Good point. I was actually thinking avg would stay as a real-only function since averaging a bunch of ints will probably result in a non-int. Maybe it can support float/double but the rest of std.math deals with reals. How about only min/max work with generic types, sum works with anything and returns long or real and avg only works with real.

Let the user decide with a second parameter.[[ ... except, if your type was (say) MyPolyType!(double), you might want to upgrade it to a MyPolyType!(real) ... nice idea, but probably never required. ]] Does sqr() deserve to be in there? It doesn't add any value that I can see.

yeah - the only thing I could think of was that expr needs to be written out twice expr*expr instead of once sqr(expr). But that's not worth a whole function, I agree.

Any time you need to write something twice you've introduced the potential for error (during maintenance, or just by having a side effect) and made the code harder to read. It stays.Likewise, all the auxilliary trig funcs (cot, sec, cosec, coth,..) can be trivially generated from the standard ones. I think that unless there's some accuracy subtleties or a speed advantage, it's hard to justify something so simple. Especially since the use of asm in that case probably _inhibits_ optimisation! eg 2.5 * cot(x) should become 2.5/tan(x).

agreed. deprecate.

So you're going to deprecate all the trigonometric functions, since they are all simple relationships on pi? These do provide an important purpose: they tell the reader what he's doing, instead of telling him how he's doing it. Would you really see "1 / sin (x)" and go "oh right he's getting the cosecant", particularly if that's embedded in a much larger calculation?

Aug 18 2005

A comment about your templates for max,min: with sum and avg, when using floats/doubles, you should be accumulating in a real. Likewise ints should accumulate in a long. Might be nice to also have a template for these cases which returned 'long' for integral types, 'real' for floats, ireal for imaginary, creal for complex, and passed user defined types straight through.

Good point. I was actually thinking avg would stay as a real-only function since averaging a bunch of ints will probably result in a non-int. Maybe it can support float/double but the rest of std.math deals with reals. How about only min/max work with generic types, sum works with anything and returns long or real and avg only works with real.

Let the user decide with a second parameter.

What do you mean?Does sqr() deserve to be in there? It doesn't add any value that I can see.

yeah - the only thing I could think of was that expr needs to be written out twice expr*expr instead of once sqr(expr). But that's not worth a whole function, I agree.

Any time you need to write something twice you've introduced the potential for error (during maintenance, or just by having a side effect) and made the code harder to read. It stays.

sheesh - you're a flexible one aren't ya. :-) fine, it stays (hands on hips)Likewise, all the auxilliary trig funcs (cot, sec, cosec, coth,..) can be trivially generated from the standard ones. I think that unless there's some accuracy subtleties or a speed advantage, it's hard to justify something so simple. Especially since the use of asm in that case probably _inhibits_ optimisation! eg 2.5 * cot(x) should become 2.5/tan(x).

agreed. deprecate.

So you're going to deprecate all the trigonometric functions, since they are all simple relationships on pi? These do provide an important purpose: they tell the reader what he's doing, instead of telling him how he's doing it. Would you really see "1 / sin (x)" and go "oh right he's getting the cosecant", particularly if that's embedded in a much larger calculation?

I agree cosecant and friends do come up but hyperbolic arccotangent? yikes. But since you're standing up for them I'll let Don see if he cares enough to argue (ps - I don't really care if they stay or go).

Aug 18 2005

Ben Hinkle wrote:

Good point. I was actually thinking avg would stay as a real-only function since averaging a bunch of ints will probably result in a non-int. Maybe it can support float/double but the rest of std.math deals with reals. How about only min/max work with generic types, sum works with anything and returns long or real and avg only works with real.

Let the user decide with a second parameter.

What do you mean?Does sqr() deserve to be in there? It doesn't add any value that I can see.

yeah - the only thing I could think of was that expr needs to be written out twice expr*expr instead of once sqr(expr). But that's not worth a whole function, I agree.

Any time you need to write something twice you've introduced the potential for error (during maintenance, or just by having a side effect) and made the code harder to read. It stays.

Well, you could write pow(expr, 2). A problem I have with sqr() is that some languages use "sqr" instead of "sqrt" (VB perhaps?).So you're going to deprecate all the trigonometric functions, since they are all simple relationships on pi?

No, there are subtleties involved in some functions. These do provide an importantpurpose: they tell the reader what he's doing, instead of telling him how he's doing it. Would you really see "1 / sin (x)" and go "oh right he's getting the cosecant", particularly if that's embedded in a much larger calculation?

Personally, I always hate seeing "cosec" in a formula, I always translate it into 1/sin in my head ... but that's just my prejudice. I don't really have a problem with any of these functions being included, but there is a philosophical question... how many functions will there eventually be in std.math ? I can see three options: (a) Follow C, and C++ with a minimalist approach to std.math, and deprecate those functions. (b) Include them in std.math, even if it means std.math will eventually become very large. (c) Put trivial derived functions in a seperate file. Maybe std.math2 ? :-) In any case, I do think it is important to have a policy, so that it is reasonably predictable where functions will be, rather than an ad-hoc approach.

Aug 18 2005

I don't really have a problem with any of these functions being included, but there is a philosophical question... how many functions will there eventually be in std.math ? I can see three options: (a) Follow C, and C++ with a minimalist approach to std.math, and deprecate those functions. (b) Include them in std.math, even if it means std.math will eventually become very large. (c) Put trivial derived functions in a seperate file. Maybe std.math2 ? :-) In any case, I do think it is important to have a policy, so that it is reasonably predictable where functions will be, rather than an ad-hoc approach.

That's a good question. Another concern I have is where to put the complex functions. Note std.math has sqrt(creal) already (I imagine to nicely overload the other sqrts) and more overloads will come soon. Given D's overloading rules I think std.math is going to get big. I am in the process of adding abs(creal) which just calls hypot. I'm not going to bother to add overloads for the pure-imaginary types but for completeness I wouldn't be surprised if they end up in there. If the complex functions went into another module I'd say they should have a "c" prefix since mixing real and creal will be common when doing complex math. I think a big std.math is ok, though. The compiler is fast. The doc is manageable. And one doesn't have to guess if a function is trivial or not enough to import std.math or std.math2.

Aug 19 2005

In article <de3ma1$1325$1 digitaldaemon.com>, Don Clugston says...Ben Hinkle wrote:

Good point. I was actually thinking avg would stay as a real-only function since averaging a bunch of ints will probably result in a non-int. Maybe it can support float/double but the rest of std.math deals with reals. How about only min/max work with generic types, sum works with anything and returns long or real and avg only works with real.

Let the user decide with a second parameter.

What do you mean?Does sqr() deserve to be in there? It doesn't add any value that I can see.

yeah - the only thing I could think of was that expr needs to be written out twice expr*expr instead of once sqr(expr). But that's not worth a whole function, I agree.

Any time you need to write something twice you've introduced the potential for error (during maintenance, or just by having a side effect) and made the code harder to read. It stays.

Well, you could write pow(expr, 2). A problem I have with sqr() is that some languages use "sqr" instead of "sqrt" (VB perhaps?).So you're going to deprecate all the trigonometric functions, since they are all simple relationships on pi?

No, there are subtleties involved in some functions. These do provide an importantpurpose: they tell the reader what he's doing, instead of telling him how he's doing it. Would you really see "1 / sin (x)" and go "oh right he's getting the cosecant", particularly if that's embedded in a much larger calculation?

Personally, I always hate seeing "cosec" in a formula, I always translate it into 1/sin in my head ... but that's just my prejudice. I don't really have a problem with any of these functions being included, but there is a philosophical question... how many functions will there eventually be in std.math ? I can see three options: (a) Follow C, and C++ with a minimalist approach to std.math, and deprecate those functions. (b) Include them in std.math, even if it means std.math will eventually become very large. (c) Put trivial derived functions in a seperate file. Maybe std.math2 ? :-) In any case, I do think it is important to have a policy, so that it is reasonably predictable where functions will be, rather than an ad-hoc approach.

(c) makes sense to me.. I think probably the original idea behind math2 was: std.math was supposed to contain basically what a C programmer would expect in math.h, and then 'std.math2' would contain other things that really belong in a math lib. somewhere (for example, abs is in C's stdlib.h). I like your idea - get everything important in std.math regardless of what a C progammer would intuit, and put the less often used functions in std.math2.

Aug 19 2005

(b) Include them in std.math, even if it means std.math will eventually become very large.

What actually would be really cool is having generic algorithms to compute the various special functions (probably just using something brute-force like the power series) and use those for complex and arbitrary-precision versions (see http://home.comcast.net/~benhinkle/gmp-d/). That would be really cool to have all the standard math functions (including min/max and friends) that just work for ints, reals, creals and arbitrary-precision floats. I should add arbitrary-precision complex to gmp-d and then that could work, too. Anyway... I'm just dreaming out loud here about what a *nice* std.math would look like. :-)

Aug 19 2005

Ben Hinkle wrote:(b) Include them in std.math, even if it means std.math will eventually become very large.

What actually would be really cool is having generic algorithms to compute the various special functions (probably just using something brute-force like the power series) and use those for complex and arbitrary-precision versions (see http://home.comcast.net/~benhinkle/gmp-d/). That would be really cool to have all the standard math functions (including min/max and friends) that just work for ints, reals, creals and arbitrary-precision floats. I should add arbitrary-precision complex to gmp-d and then that could work, too. Anyway... I'm just dreaming out loud here about what a *nice* std.math would look like. :-)

I'm not entirely sure that the generic functions like min(), sum() belong in std.math. But, if there were generic algorithms for power series, I might change my mind. My "gut feel" is that std.math is for functions that operate on and return real numbers, std.complex or std.cmath would operate on complex or imaginary numbers. Template functions like "min" could be applied in non-mathematical contexts (eg, you might want to find the smallest FunkyWidget), One possibility is to follow the STL from C++ and create a std.algorithm. Of course the STL made some very strange decisions, accumulate() isn't with the other functions, for example. ---- With Walters comment about Pavel's copyright, I suggest that std.math2 be moved to etc for the time being. Or at least, don't bother documenting it. Just throw abs() into std.math, it's important and trivial.

Aug 21 2005

"Don Clugston" <dac nospam.com.au> wrote in message news:deb35e$1rre$1 digitaldaemon.com...Ben Hinkle wrote:(b) Include them in std.math, even if it means std.math will eventually become very large.

What actually would be really cool is having generic algorithms to compute the various special functions (probably just using something brute-force like the power series) and use those for complex and arbitrary-precision versions (see http://home.comcast.net/~benhinkle/gmp-d/). That would be really cool to have all the standard math functions (including min/max and friends) that just work for ints, reals, creals and arbitrary-precision floats. I should add arbitrary-precision complex to gmp-d and then that could work, too. Anyway... I'm just dreaming out loud here about what a *nice* std.math would look like. :-)

I'm not entirely sure that the generic functions like min(), sum() belong in std.math. But, if there were generic algorithms for power series, I might change my mind.

Where would you put min/sum/etc?My "gut feel" is that std.math is for functions that operate on and return real numbers, std.complex or std.cmath would operate on complex or imaginary numbers.

The problem with using multiple modules is that D's overloading rules are very strict and so user code can't import both std.math and std.complex and freely mix calls to functions overloaded between modules. So for example if sin was defined in std.math and std.complex then writing sin(x) would be illegal - it would have to be explicitly written as std.math.sin(x) or std.complex.sin(x) or users would have to alias sin in the current module. So with D if there's a chance two modules will be used at the same time they should not overload each other. Personally I think using std.math for "all things mathematical" is natural. Even mathematical operations like min/max that can be applied to anything that overloads < or > or whatever. It's still most commonly used as a mathematical operation. Maybe we need std.math and std.mathwannabes.Template functions like "min" could be applied in non-mathematical contexts (eg, you might want to find the smallest FunkyWidget), One possibility is to follow the STL from C++ and create a std.algorithm. Of course the STL made some very strange decisions, accumulate() isn't with the other functions, for example.

Sounds reasonable - and std.math can import whatever has the min/max/etc so that user code doesn't have to import lots of stuff just to do basic math operations.

Aug 22 2005

Ben Hinkle wrote:"Don Clugston" <dac nospam.com.au> wrote in message news:deb35e$1rre$1 digitaldaemon.com...Ben Hinkle wrote:(b) Include them in std.math, even if it means std.math will eventually become very large.

What actually would be really cool is having generic algorithms to compute the various special functions (probably just using something brute-force like the power series) and use those for complex and arbitrary-precision versions (see http://home.comcast.net/~benhinkle/gmp-d/). That would be really cool to have all the standard math functions (including min/max and friends) that just work for ints, reals, creals and arbitrary-precision floats. I should add arbitrary-precision complex to gmp-d and then that could work, too. Anyway... I'm just dreaming out loud here about what a *nice* std.math would look like. :-)

I'm not entirely sure that the generic functions like min(), sum() belong in std.math. But, if there were generic algorithms for power series, I might change my mind.

Where would you put min/sum/etc?

These functions switch on the traits of a comparable type - there are also traits for arrays, strings, numerics, integrals, fractionals and complex (that's where std.math comes in), and others to work with. A library organisation could have it as: module std.tcomparable; template TComparable(T) { T min(T[] list...) { assert (list.length); T result = list[0]; foreach (T item; list[1..$]) if (item < result) result = item; return result; } } But I don't think it's worth doing this to Phobos, because it's such a large restructuring. By the way, that's the only implementation of min you need - you can pass an array to a variadics-array-taking function.My "gut feel" is that std.math is for functions that operate on and return real numbers, std.complex or std.cmath would operate on complex or imaginary numbers.

The problem with using multiple modules is that D's overloading rules are very strict and so user code can't import both std.math and std.complex and freely mix calls to functions overloaded between modules. So for example if sin was defined in std.math and std.complex then writing sin(x) would be illegal - it would have to be explicitly written as std.math.sin(x) or std.complex.sin(x) or users would have to alias sin in the current module. So with D if there's a chance two modules will be used at the same time they should not overload each other.

Yeah, it's a real pain in the ass how D makes writing functions a mandatory part of its engineering but supports them so horribly. The same problem applies to mixins. The claim is that this way prevents bugs, but what it really does is put pitfalls into developing and maintaining code. D's very simple function overloading will still catch any ambiguous conflict.Personally I think using std.math for "all things mathematical" is natural. Even mathematical operations like min/max that can be applied to anything that overloads < or > or whatever. It's still most commonly used as a mathematical operation. Maybe we need std.math and std.mathwannabes.Template functions like "min" could be applied in non-mathematical contexts (eg, you might want to find the smallest FunkyWidget), One possibility is to follow the STL from C++ and create a std.algorithm. Of course the STL made some very strange decisions, accumulate() isn't with the other functions, for example.

Sounds reasonable - and std.math can import whatever has the min/max/etc so that user code doesn't have to import lots of stuff just to do basic math operations.

Aug 22 2005

Where would you put min/sum/etc?

These functions switch on the traits of a comparable type - there are also traits for arrays, strings, numerics, integrals, fractionals and complex (that's where std.math comes in), and others to work with. A library organisation could have it as: module std.tcomparable; template TComparable(T) { T min(T[] list...) { assert (list.length); T result = list[0]; foreach (T item; list[1..$]) if (item < result) result = item; return result; } } But I don't think it's worth doing this to Phobos, because it's such a large restructuring.

I don't follow - what large restructuring? Aren't we just talking about std.math2?By the way, that's the only implementation of min you need - you can pass an array to a variadics-array-taking function.

Neat. I didn't know that.

Aug 22 2005

Ben Hinkle wrote:Where would you put min/sum/etc?

These functions switch on the traits of a comparable type - there are also traits for arrays, strings, numerics, integrals, fractionals and complex (that's where std.math comes in), and others to work with. A library organisation could have it as: module std.tcomparable; template TComparable(T) { T min(T[] list...) { assert (list.length); T result = list[0]; foreach (T item; list[1..$]) if (item < result) result = item; return result; } } But I don't think it's worth doing this to Phobos, because it's such a large restructuring.

I don't follow - what large restructuring? Aren't we just talking about std.math2?

I mean that min/max is part of a much broader set of template mixins that have specialised, stunted forms all throughout Phobos; std.string is a specialisation of a string mixin, std.math is a fractional mixin (specifically a specialisation on the floating-point types to use the intrinsics - the general form would use approximating algorithms), array properties are a miniscule subset of an array mixin. It would be very valuable to have those templates in a standard library; they'd have richer functionality and they would work with user types. However, I don't think it's worth trying to reform Phobos to such an extent. I'm not talking about a template library like MinTL - instead one that purely functions with the builtin types.

Aug 23 2005

"Charles" <noone nowhere.com> wrote in message news:de3034$fhe$1 digitaldaemon.com...Not sure why math2 even exists, why not throw them all in math ?

Because of Pavel's copyright on it. The stuff needs to be reimplemented to get around it, or math2 needs to be moved into etc.

Aug 21 2005

While we're on the subject, here's another quick function which exposes the x86 "fsincos" asm instruction. C99 considered including cis() but eventually rejected it; but I think the argument is stronger for D since (a) D has mandated the use of IEEE floats (and therefore x86 is a very significant platform), and (b) complex reals are more strongly embedded in the language. Might belong in std.cmath or std.complex, rather than std.math. ------------------------------------------------- SOME DOC CHANGES FOR std.math: The documentation for sin(x) in VC++2003 states: "If x is greater than or equal to 2^63, or less than or equal to -2^63 a loss of significance in the result occurs." That's a massive understatement. In fact, outside this range the results from the fsin, fcos instructions are nonsense. sin(1e20) returns 1e20. So the docs for sin(x), cos(x), cis(x) should state: "sin(x) is valid only for abs(x) < 0x1p+63 (approx 9e18). Outside this range, the results are undefined." tan(x) seems to be unaffected by this. Also, in the "constants" section, it might be helpful to add the line: "These are the closest representable numbers to the corresponding mathematical constant. Because the precision is not infinite, results may not be what you expect. For example, sin(2*PI) will not be <i>exactly<i> zero; instead, it will be about 1e-20 on most systems." There should be one line descriptions of what each constant is, as well. Trivial, but it would bring the docs closer to 1.0. -Don. ------------------------------------------------------ // cis(theta) = cos(theta) + sin(theta)i. version (X86) { // On x86, this is almost twice as fast as sin(x) + 1.0i*cos(x). creal cis(real x) { asm { fld x; fsincos; fxch st(1), st(0); } } } else { creal cis(real x) { return cos(x) + sin(x)*1i; } } unittest { assert(cis(0)==1+0i); assert(cis(1.3e5)==cos(1.3e5)+sin(1.3e5)*1i); creal c = cis(real.nan); assert(isnan(c.re) && isnan(c.im)); c = cis(real.infinity); assert(isnan(c.re) && isnan(c.im)); }

Aug 21 2005