From: Libor S. <li...@gm...> - 2008-07-07 14:52:57
|
Forgive me for raising this topic again, I seem to recall that is was touched upon, and rejected, when we were discussing the introduction of "|". However, attempting to reach some kind of polymorphism while maximising the efficiency benefits of "::", I find myself repeatedly writing code of the form: somefun ...... numarg::int | somefun ...... numarg::bigint | soomefun ..... numarg::double = .....; Firstly, when it is only the last argument's type changing, it should be possible to write: somefun ....... numarg::int::bigint::double = .......; without introducing an exponential explosion. However, I understand that this could be considered quirky and so it is not my main point. A better solution would be to instroduce a generic ::number, justified by the general importance of numbers :) somefun ....... numarg::number = ......; // now writes and reads much easier On a related topic, I had to write my own mod definition that also works on doubles and this somewhat eased the above problem: // mod of a double x::double mod y::int = (x - intx) + (intx mod y) when intx = (int x) end; I understand that if I use math.pure, I can do anything I want, as in C but this is more a matter of having a convenient basic facility in the default pure, leading to ease of polymorphic coding. I also realise that the exclusion of doubles from the pure mod is probably trying to be consistent with the C usage (mod versus modf). However, C does not have the polymorphism. So, is there an overriding reason for NOT including my modification in the pure's default mod? Plus carrying out modifications in the same spirit to other similar functions? In general, in such cases, I don't think it is particularly dangerous or surprising for users to get a double out when they supply a double as input. I find it more unsettling and bothersome "down the line" when it currently just fails to evaluate. Regards, Libor |
From: Albert G. <Dr....@t-...> - 2008-07-07 17:48:27
|
Libor Spacek wrote: > A better solution would be to instroduce a generic ::number, justified by the general importance of numbers :) > > somefun ....... numarg::number = ......; // now writes and reads much easier That opens a can of worms. I've really given this some thought, and even coughed up a syntax to define "derived" type tags like this, but it's just not feasible. It would seem rather odd if derived tags could only be used once on the lhs of an equation, but otherwise just a little sloppy coding makes your code size explode combinatorically. There's already the Lispy way to deal with this kind of ad hoc polymorphism, namely just forget about the type tags; if necessary, add a call to numberp or some such predicate to the guard. In most cases this will be fast enough. In some cases it certainly makes sense to optimize the definitions, but then you'll just have to use multiple lhs. Which also keeps you painfully aware that you're actually defining multiple rules, but that's intended. ;-) > // mod of a double > x::double mod y::int = (x - intx) + (intx mod y) when intx = (int x) end; If memory serves me, Common Lisp has this, but not any Algol-like language I know. I can add it to math.pure if there's enough demand. > I also realise that the exclusion of doubles from the pure mod is probably trying to be consistent > with the C usage (mod versus modf). No, it's trying to be consistent with 'div' which doesn't take a double as its first operand either. Same as in Algol 60 and its successors, not C. Cheers, Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Eddie R. <er...@bm...> - 2008-07-07 21:20:28
|
> > // mod of a double > > x::double mod y::int = (x - intx) + (intx mod y) when intx = (int x) end; > > If memory serves me, Common Lisp has this, but not any Algol-like > language I know. I can add it to math.pure if there's enough demand. I've had to deal with this once in Pascal somewhere before but I cant recall. In that occasion I found that mod(double, double) may be defined in two ways in order to stay consistent with something else ... Dang I can't find it on google. I don't know if you should add "double mod double" to the list or not but I sure would hate to have to look it up again. If memory servers me (probably doesn't) C's definition of fmod really should be called frem instead because there is a difference between real mod and real remainder. I guess I better shut up now before I stick my foot in my mouth. e.r. |
From: Libor S. <li...@gm...> - 2008-07-07 22:50:30
|
Eddie, you are right that C's fmod is different. What I was after was just "double mod int" which seems pretty innocuous to me. I have defined it myself and it saved me lots of lines of repetitious code to duplicate everything for ::int and ::double, so I thought others might also benefit from its addition. I note what Albert had to say on the matter and it is OK by me. It is no big deal, I can live with my own definition if it is not added. Albert did mention div which is a similar beast. Various misguided historical precedents notwithstanding, I would prefer the following behaviour: Both to accept all types of numerical arguments. div to "narrow" ie. if either argument is an int, return int / to "widen", ie. if either argument is a double, return double This is more forgiving and consistent, therefore imho more in the "pure" spirit. However, I guess ultimately it is just a personal preference. L. On Mon, 07 Jul 2008 22:20:35 +0100, Eddie Rucker <er...@bm...> wrote: >> > // mod of a double >> > x::double mod y::int = (x - intx) + (intx mod y) when intx = (int x) end; >> >> If memory serves me, Common Lisp has this, but not any Algol-like >> language I know. I can add it to math.pure if there's enough demand. > > I've had to deal with this once in Pascal somewhere before but I cant > recall. In that occasion I found that mod(double, double) may be defined > in two ways in order to stay consistent with something else ... Dang I > can't find it on google. > > I don't know if you should add "double mod double" to the list or not > but I sure would hate to have to look it up again. If memory servers me > (probably doesn't) C's definition of fmod really should be called frem > instead because there is a difference between real mod and real > remainder. I guess I better shut up now before I stick my foot in my > mouth. > > e.r. > > > ------------------------------------------------------------------------- > Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW! > Studies have shown that voting for your favorite open source project, > along with a healthy diet, reduces your potential for chronic lameness > and boredom. Vote Now at http://www.sourceforge.net/community/cca08 > _______________________________________________ > pure-lang-users mailing list > pur...@li... > https://lists.sourceforge.net/lists/listinfo/pure-lang-users > |
From: Eddie R. <er...@bm...> - 2008-07-07 23:25:29
|
On Mon, 2008-07-07 at 23:50 +0100, Libor Spacek wrote: > Eddie, you are right that C's fmod is different. > What I was after was just "double mod int" which seems pretty innocuous > to me. I have defined it myself and it saved me lots of lines of repetitious > might also benefit from its addition. Ok. In this case it seems logical to convert the int parameter to double and use fmod to me. e.r. |
From: Albert G. <Dr....@t-...> - 2008-07-07 23:29:05
|
Libor Spacek wrote: > Both to accept all types of numerical arguments. Ok, do you have definitions of div and mod for all other cases? Note that then we also need definitions for the rational and complex numbers in math.pure. I must admit that I never gave this much thought. Pure inherited div and mod from Q which inherited them from Pascal which in turn inherited them (I guess) from Algol 60. I'm not against extending them in a reasonable manner. :) Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Libor S. <li...@gm...> - 2008-07-08 10:09:41
|
I was not really thinking about rationals and complex numbers and anything else yet. Just int, bigint and double, so far. Though I expect others could be extended in the same "permissive" spirit. Here are my defs for ndiv and slash (new /). In practice, you could of course just add these extra cases to the existing definitions without using new symbols: infixl 7 ndiv; x::double ndiv y = int x div y; x ndiv y::double = int (x/y); x ndiv y = x div y; > list slash infixl 7 slash; x::int slash y::int = x div y if x mod y==0; x slash y = x/y; I think they might be conformant with Eddie's implicit definition. Libor On Tue, 08 Jul 2008 00:29:05 +0100, Albert Graef <Dr....@t-...> wrote: > Ok, do you have definitions of div and mod for all other cases? Note > that then we also need definitions for the rational and complex numbers > in math.pure. > > I must admit that I never gave this much thought. Pure inherited div and > mod from Q which inherited them from Pascal which in turn inherited them > (I guess) from Algol 60. I'm not against extending them in a reasonable > manner. :) > > Albert > |
From: Albert G. <Dr....@t-...> - 2008-07-08 12:18:28
|
Libor Spacek wrote: > I was not really thinking about rationals and complex numbers and anything else yet. Yes, but at least the rationals have to work, too. > Here are my defs for ndiv and slash (new /). In practice, you could of course just add > these extra cases to the existing definitions without using new symbols: This will have to be so, since I don't want to have more division operators in the library, unless there's a *really* compelling reason for them. > infixl 7 slash; > x::int slash y::int = x div y if x mod y==0; > x slash y = x/y; A division operator which returns ints only if x divides y? I don't think that this is a good idea, as you never know which type is returned. The rationale behind / is precisely that you *always* get a double result, same with '^'. That's the Algol philosophy and I think it's good; I won't change it. div/mod is another business; as long as they work consistently with the integer div/mod and they cover all appropriate cases including rationals I'm willing to add the extensions. Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Libor S. <li...@gm...> - 2008-07-08 14:04:55
|
On Tue, 08 Jul 2008 13:18:16 +0100, Albert Graef <Dr....@t-...> wrote: > A division operator which returns ints only if x divides y? I don't > think that this is a good idea, as you never know which type is > returned. The rationale behind / is precisely that you *always* get a > double result, same with '^'. That's the Algol philosophy and I think > it's good; I won't change it. > > div/mod is another business; as long as they work consistently with the > integer div/mod and they cover all appropriate cases including rationals > I'm willing to add the extensions. > > Albert > OK, fair enough. I was working up to the "mad" idea which is probably too revolutionary and upsetting to everyone. The idea is that all the current numeric types become transparent (hidden) to the user. Promotions take place automatically (in the background) whenever a loss of information would otherwise occur, such as: int becoming too big -> bigint x div y -> rational (if y does not divide x) sqrt (-2) -> complex and demotions too: bigint that fits into an int -> int rational that simplifies to an int or bigint -> int or bigint complex with imaginary part == 0 -> real The hidden old style type would then be used only for deciding how to present the result. Also, replace doubles with rationals. (All numbers with limited precision are de facto rationals anyway). For pragmatic reasons place some limit on the size of the bigints and raise an exception when it is reached. I guess to really fly, this would need to be taken up by the processor manufacturers, to add rational instructions. The beauty of this scheme is that you could then get away with having just ::number type and nothing else and use only one common code for any calculations, instead of the current, frankly, mess. Libor |
From: Eddie R. <er...@bm...> - 2008-07-08 14:54:41
|
On Tue, 2008-07-08 at 15:05 +0100, Libor Spacek wrote: > OK, fair enough. I was working up to the "mad" idea which is probably too revolutionary and upsetting to everyone. Sorry, but I don't know enough to be upset ;-) > The idea is that all the current numeric types become transparent (hidden) to the user. Promotions take place automatically (in the background) whenever a loss of information would otherwise occur, such as: > and demotions too: Scheme does some of this except numbers are separated into two groups "exact" and "inexact." The only explicit conversions required are between exact and inexact except were it really makes since like (sqrt 5). Demotions of inexact (floating point) to exact is the only thing missing but for good reason see (sqrt 1/5) below. Example: > (/ 4 3) 1 1/3 Note the space between 1 and 1/3. MzScheme returns a mixed number. > (/ 4.0 3) 1.3333333333333333 > (/ 4 3.0) 1.3333333333333333 > (sqrt 4.0) 2.0 > (sqrt 4) 2 > (sqrt 4/9) 2/3 > (sqrt 1/5) 0.4472135954999579 We don't want and exact approximation to an irrational number do we? Yes, I know that is really a rational number in disguise, but it lets the user know that it really is an approximation instead of letting them believe it is exact. > (expt 4 1/2) 2 > (sqrt -4) 0+2i > (expt -4 1/2) 0+2i > (sqrt -4.0) 0+2.0i > (expt > (inexact->exact 0.123) 553942754166571/4503599627370496 e.r. |
From: Libor S. <li...@gm...> - 2008-07-08 15:38:46
|
Better still, as there is an internal structure associated with this extended number representation, we could include a binary "exact" flag that can be interrogated by the user at any point to tell them which it is. Libor |
From: Albert G. <Dr....@t-...> - 2008-07-09 05:19:26
|
Eddie Rucker wrote: > > rationalp 1; > 0 > > Oops, Albert 1 is a rational number, so I think rationalp has a bug? No, I only implemented the syntactic number predicates so far, still have to add the semantic ones. -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Albert G. <Dr....@t-...> - 2008-07-09 05:03:37
|
Libor Spacek wrote: > The idea is that all the current numeric types become transparent (hidden) to the user. As Eddie already pointed out, that's the idea behind Scheme's numeric tower; that's probably as far as you can go to alleviate the complexities of the numeric tower before hitting the wall of computational complexity. I've already explained in another thread why Pure doesn't follow Scheme's scheme in order to achieve its goals, so I won't rehash this discussion here. In any case Pure makes it easy to write polymorphic functions which work with all numeric types without a big runtime penalty, and also makes it easy to distinguish them when it's necessary. There are a few inconveniences where you have to use explicit conversions to tell the interpreter which kind of result you actually want, but I think that they're relatively minor. YMMV. But at least Pure allows you to add your own equations to existing operations to patch them up the way you want them, like you did with the mod operation. > The beauty of this scheme is that you could then get away with having just ::number type and nothing else and use only one common code for any calculations, instead of the current, frankly, mess. Yeah, one can dream. But there's always the tradeoff between speed and convenience, that's why we still need machine ints and floating point numbers. "If you can't make it both fast and correct, make it fast." ;-) Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Albert G. <Dr....@t-...> - 2008-08-14 16:25:54
|
John Cowan wrote: > The problem is that floating-point underflow gives 0 silently, so a result > can become real when mathematically it should not. That's true, but the same kind of argument could also be used to argue that 3.0 should not be considered "integer" either. > Is polar representation a major consideration in Pure? Yes. Both notations are equally important and can be used interchangeably. We discussed this here, and it was considered a very useful feature. > I don't know any language supporting complex numbers where it is. Well, many advanced calculators all have it, if that counts. ;-) That's no accident; the polar representation is much more convenient when doing signal processing stuff and in general everything that involves lots of products and powers of complex numbers. Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: John C. <co...@cc...> - 2008-08-14 16:34:01
|
Albert Graef scripsit: > > The problem is that floating-point underflow gives 0 silently, so a result > > can become real when mathematically it should not. > > That's true, but the same kind of argument could also be used to argue > that 3.0 should not be considered "integer" either. Touché. -- All Gaul is divided into three parts: the part John Cowan that cooks with lard and goose fat, the part http://ccil.org/~cowan that cooks with olive oil, and the part that co...@cc... cooks with butter. --David Chessler |
From: Albert G. <Dr....@t-...> - 2008-08-14 13:26:08
|
Albert Graef wrote: > Eddie Rucker wrote: >> > rationalp 1; >> 0 >> >> Oops, Albert 1 is a rational number, so I think rationalp has a bug? > > No, I only implemented the syntactic number predicates so far, still > have to add the semantic ones. These are implemented now. (Mostly untested so far.) They should work the same as in Q, except that realvalp considers any complex value with zero imaginary part a real value. (In Q realvalp requires that the imaginary part is an exact zero, which would be rather inconvenient in Pure because that rules out most complex values in polar representation.) Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: John C. <co...@cc...> - 2008-08-14 15:01:16
|
Albert Graef scripsit: > (In Q realvalp requires that the > imaginary part is an exact zero, which would be rather inconvenient in > Pure because that rules out most complex values in polar representation.) The problem is that floating-point underflow gives 0 silently, so a result can become real when mathematically it should not. Is polar representation a major consideration in Pure? I don't know any language supporting complex numbers where it is. -- You're a brave man! Go and break through the John Cowan lines, and remember while you're out there co...@cc... risking life and limb through shot and shell, http://ccil.org/~cowan we'll be in here thinking what a sucker you are! --Rufus T. Firefly |
From: Albert G. <Dr....@t-...> - 2008-07-08 07:44:21
|
Eddie Rucker wrote: > A reasonable manner suggests x = (x mod N) + (x div N) * N ... where x div N is integer and abs (x mod N) < abs N I guess, with x mod N the same sign as x? That implicit definition should work with any combination of real-valued operands (provided that N is nonzero, of course). Division of a complex by a real could be lifted from that, but I'm not sure whether we actually want it? Then there's still the question whether x div n should be the same type as x or n. x mod n is of course the same type as x. And we need to decide what to do with division by zero. Machine int and bigint division both raise a SIGFPE right now (at least on Linux), which is a bit inconvenient. ;-) They could be made undefined like in Q. That will complicate and slow down the code for machine int division, though; right now this is just a single sdiv instruction. Therefore I'd prefer to install a signal handler which maps SIGFPE to a corresponding Pure exception; that wouldn't incur runtime costs. In any case rational division should follow suit (it returns a floating point infinity right now). Opinions? > By the way, I noticed my MzScheme only accepts integers for both the > modulo and remainder functions. Then it probably follows R5RS. AFAICT R6RS specifies div and mod (and variations) which work with all real (but not with complex) arguments. Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Eddie R. <er...@bm...> - 2008-07-08 12:24:44
|
On Tue, 2008-07-08 at 09:44 +0200, Albert Graef wrote: > Eddie Rucker wrote: > > A reasonable manner suggests x = (x mod N) + (x div N) * N > > ... where x div N is integer and abs (x mod N) < abs N I guess, with x > mod N the same sign as x? Yes. > That implicit definition should work with any combination of real-valued > operands (provided that N is nonzero, of course). Division of a complex > by a real could be lifted from that, but I'm not sure whether we > actually want it? Please don't implement the complex stuff. Implementing mathematics libraries is kind of like boxing, unless you spend a lot of time in the ring, you are going to get your jaw jacked. In my *very humble opinion*, if we want to implement anything, that would be mod and div operators that obey Scheme's R6RS rules as you alluded to below. > And we need to decide what to do with division by zero. Machine int and > bigint division both raise a SIGFPE right now (at least on Linux), which > is a bit inconvenient. ;-) They could be made undefined like in Q. That > will complicate and slow down the code for machine int division, though; > right now this is just a single sdiv instruction. Therefore I'd prefer > to install a signal handler which maps SIGFPE to a corresponding Pure > exception; that wouldn't incur runtime costs. In any case rational > division should follow suit (it returns a floating point infinity right > now). Opinions? Hmmm. I really don't know. Playing around with computer mathematics is one thing. Getting it right for the masses is a *monster*. Maybe bring it up before other language designers and see what they say. > Then it probably follows R5RS. AFAICT R6RS specifies div and mod (and > variations) which work with all real (but not with complex) arguments. It looks like they ditched quotient, remainder, and modulo for new functions div, div0, mod, mod0, div-and-mod, and div0-and-mod0. I'm not sure I want to vote for anything right now. e.r. |
From: Albert G. <Dr....@t-...> - 2008-07-09 05:22:19
|
Eddie Rucker wrote: > exactp n = not (doublep n || doublep (re n) || doublep (im n)); Yes, that looks like it could work, and it's better than my definition in math.pure. There's a guard if numberp n missing in your version, though. -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Eddie R. <er...@bm...> - 2008-07-09 12:42:35
|
On Wed, 2008-07-09 at 07:22 +0200, Albert Graef wrote: > Eddie Rucker wrote: > > exactp n = not (doublep n || doublep (re n) || doublep (im n)); > > Yes, that looks like it could work, and it's better than my definition > in math.pure. There's a guard if numberp n missing in your version, though. Sorry, I overlooked this before, I see it at the bottom of math.pure. Actually, we should probably have an inexactp too as I have a feeling I would be checking this more that exactp as I have with Scheme's (inexact? ). Then, inexactp n = doublep n || doublep (re n) || doublep (im n) if numberp n; exactp n = not (inexactp n) if numberp n; e.r. |
From: Albert G. <Dr....@t-...> - 2008-07-09 19:35:52
|
Eddie Rucker wrote: > Sorry, I overlooked this before, I see it at the bottom of math.pure. > Actually, we should probably have an inexactp too as I have a feeling I > would be checking this more that exactp as I have with Scheme's > (inexact? ). Then, > > inexactp n = doublep n || doublep (re n) || doublep (im n) if numberp > n; > exactp n = not (inexactp n) if numberp n; Agreed. Well, maybe you should keep the explicit definition of exactp, too, so that numberp doesn't need to be called twice. Can you commit those changes, please? Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |
From: Eddie R. <er...@bm...> - 2008-07-07 23:39:48
|
On Tue, 2008-07-08 at 01:29 +0200, Albert Graef wrote: > Ok, do you have definitions of div and mod for all other cases? Note > that then we also need definitions for the rational and complex numbers > in math.pure. > > I must admit that I never gave this much thought. Pure inherited div and > mod from Q which inherited them from Pascal which in turn inherited them > (I guess) from Algol 60. I'm not against extending them in a reasonable > manner. :) A reasonable manner suggests x = (x mod N) + (x div N) * N. I didn't make this up. By the way, I noticed my MzScheme only accepts integers for both the modulo and remainder functions. e.r. |
From: Libor S. <li...@gm...> - 2008-07-08 10:17:11
|
Oh, you will also need: x::bigint ndiv y::double = bigint (x/y) but hopefully, the idea is clear? L. |
From: Albert G. <Dr....@t-...> - 2008-07-08 12:22:39
|
Libor Spacek wrote: > Oh, you will also need: > > x::bigint ndiv y::double = bigint (x/y) > > but hopefully, the idea is clear? Yes, sure, but where's the code? :) If someone is willing to code this and check that it really works (which also entails writing a unit test), I'm going to add it to the library. Albert -- Dr. Albert Gr"af Dept. of Music-Informatics, University of Mainz, Germany Email: Dr....@t-..., ag...@mu... WWW: http://www.musikinformatik.uni-mainz.de/ag |