digitalmars.D - Fixing the imaginary/complex mess
- Don (23/23) Apr 30 2009 D currently allows some conversions between complex/imaginary types and
- dsimcha (11/34) Apr 30 2009 I'm totally ok with you creating such a patch and applying it, as I don'...
- Andrei Alexandrescu (4/34) Apr 30 2009 Since you're looking into this already, I suggest we move for the kill
- Robert Fraser (3/39) Apr 30 2009 Ehhh.... why not leave complex and just kill imaginary? That'd solve
- bearophile (5/7) Apr 30 2009 You can't remove only half of a feature of the language, so I don't like...
- Robert Fraser (8/17) Apr 30 2009 It's not necessarily "removing half a feature". Imaginary numbers aren't...
- Andrei Alexandrescu (5/7) Apr 30 2009 Yah, but then I'm thinking: how many numeric literals are in a program
- Joel C. Salomon (7/9) Apr 30 2009 The reasons for a separate imaginary type are listed in the D docs at
- Don (8/42) Apr 30 2009 I'd like to actually eliminate these operations from D1. Otherwise, I
- Brad Roberts (5/12) Apr 30 2009 I think it's perfectly acceptable to not fix these in D1 and only addres...
- Don (3/17) Apr 30 2009 I think so many people are actually using D1, that ICE bugs really
- bearophile (13/16) Apr 30 2009 I agree to disallow/fix those things.
- Georg Wrede (7/37) Apr 30 2009 It might be a good idea to write in the docs why these operations are
- Don (5/44) Apr 30 2009 I don't think anyone expects to be able to divide an integer by an
- Georg Wrede (3/50) Apr 30 2009 Just goes to show you the average math knowledge. I never would have
- Walter Bright (4/7) May 03 2009 There actually is a reason - completeness. Mathematically, there is a
- Bill Baxter (6/14) May 03 2009 But the result of int divided by imaginary is pure imaginary. So I
- Don (22/30) May 04 2009 In the case complex = int/complex, there's no problem. It's the case int...
- Frits van Bommel (3/7) May 04 2009 Devil's advocate: one could argue it's the same as cast(int) of a float ...
- Don (9/18) May 04 2009 Sure, you're at liberty to argue anything. But mathematicians don't do
- Derek Parnell (9/17) May 04 2009 Hmmm. not quite because we can not do ...
- Jason House (4/12) May 04 2009 I consider this to be a much different case. Assuming the float to an in...
- bearophile (5/9) May 04 2009 I am with you. Making the language tidy is the way to go :-)
- Georg Wrede (5/38) May 04 2009 Walter, could the error message then include "Please use z.re or z.im to...
- Andrei Alexandrescu (3/7) May 04 2009 If we cut the limb, why first apply an ointment to it?
- Steven Schveighoffer (5/11) May 04 2009 I think the point is relevant to D1, where you can't really remove the
- Andrei Alexandrescu (5/28) Jun 12 2011 Don, instead of this fix, could be at best phase everything built-in
- bearophile (88/91) Jun 12 2011 Two usages of complex numbers in the RosettaCode site.
- Robert Clipsham (7/28) Jun 13 2011 I seemed to think the plan for complex numbers was to do what happened
- Lars T. Kyllingstad (7/45) Jun 13 2011 That was my understanding as well, which is why I never added a complex(...
- Andrei Alexandrescu (10/13) Jun 13 2011 No, the current vision is to completely replace complex with library
- Lars T. Kyllingstad (9/23) Jun 13 2011 Sure, I'll add complex().
- Lars T. Kyllingstad (4/10) Jun 13 2011 As promised:
- bearophile (8/10) Jun 13 2011 Before deciding I'd like to know the rationale to keep it. In principle ...
D currently allows some conversions between complex/imaginary types and real types, which are highly dubious. Given creal z, ireal y, these casts are legal: real x = cast(real)z; x = cast(real)y; // always sets x==0, regardless of the value of y. But I believe that should not be legal. For the first case, it should be written as: real x = z.re; (which is shorter and clearer), and the second case is probably a bug, and should be x = y.im; (unless the intention really was to set x=0!). By the same logic, we could have sqrt(-1)==0, since the real part is 0. The most important effect of disallowing these casts would be to fix a host of bugs and wierd behaviour. All the A op= B operations involve a cast to A. If those nonsensical casts become illegal, the nonsensical op= operations become illegal automatically. Eg, ireal y; y *= y; // mathematically nonsense, y*y is real, so can't be stored in a pure imaginary type! There are a few segfault/ICE bugs (eg 718, 2839) which involve int/=complex, an operation which never makes any sense anyway. I think we're just making problems for ourselves by allowing these useless operations. I think they should be killed. Does anyone object? (If not, I'll create a patch to do it; it's not very difficult).
Apr 30 2009
== Quote from Don (nospam nospam.com)'s articleD currently allows some conversions between complex/imaginary types and real types, which are highly dubious. Given creal z, ireal y, these casts are legal: real x = cast(real)z; x = cast(real)y; // always sets x==0, regardless of the value of y. But I believe that should not be legal. For the first case, it should be written as: real x = z.re; (which is shorter and clearer), and the second case is probably a bug, and should be x = y.im; (unless the intention really was to set x=0!). By the same logic, we could have sqrt(-1)==0, since the real part is 0. The most important effect of disallowing these casts would be to fix a host of bugs and wierd behaviour. All the A op= B operations involve a cast to A. If those nonsensical casts become illegal, the nonsensical op= operations become illegal automatically. Eg, ireal y; y *= y; // mathematically nonsense, y*y is real, so can't be stored in a pure imaginary type! There are a few segfault/ICE bugs (eg 718, 2839) which involve int/=complex, an operation which never makes any sense anyway. I think we're just making problems for ourselves by allowing these useless operations. I think they should be killed. Does anyone object? (If not, I'll create a patch to do it; it's not very difficult).I'm totally ok with you creating such a patch and applying it, as I don't use complex numbers anyhow, but if we're going to look at fixing complex numbers, shouldn't we discuss whether they even still belong in the core language? IMHO they don't because D's user defined types have advanced pretty significantly since the decision was made to put them in, and they're a *very* niche feature. The only people who need complex and imaginary numbers are scientific computing people, and not all or even most scientific computing people need them. Show of hands, how many people here actually use D's complex numbers on a regular enough basis that you would miss them if they were removed from the core language completely?
Apr 30 2009
Don wrote:D currently allows some conversions between complex/imaginary types and real types, which are highly dubious. Given creal z, ireal y, these casts are legal: real x = cast(real)z; x = cast(real)y; // always sets x==0, regardless of the value of y. But I believe that should not be legal. For the first case, it should be written as: real x = z.re; (which is shorter and clearer), and the second case is probably a bug, and should be x = y.im; (unless the intention really was to set x=0!). By the same logic, we could have sqrt(-1)==0, since the real part is 0. The most important effect of disallowing these casts would be to fix a host of bugs and wierd behaviour. All the A op= B operations involve a cast to A. If those nonsensical casts become illegal, the nonsensical op= operations become illegal automatically. Eg, ireal y; y *= y; // mathematically nonsense, y*y is real, so can't be stored in a pure imaginary type! There are a few segfault/ICE bugs (eg 718, 2839) which involve int/=complex, an operation which never makes any sense anyway. I think we're just making problems for ourselves by allowing these useless operations. I think they should be killed. Does anyone object? (If not, I'll create a patch to do it; it's not very difficult).Since you're looking into this already, I suggest we move for the kill and eliminate built-in complex. Andrei
Apr 30 2009
Andrei Alexandrescu wrote:Don wrote:Ehhh.... why not leave complex and just kill imaginary? That'd solve most of the problems.D currently allows some conversions between complex/imaginary types and real types, which are highly dubious. Given creal z, ireal y, these casts are legal: real x = cast(real)z; x = cast(real)y; // always sets x==0, regardless of the value of y. But I believe that should not be legal. For the first case, it should be written as: real x = z.re; (which is shorter and clearer), and the second case is probably a bug, and should be x = y.im; (unless the intention really was to set x=0!). By the same logic, we could have sqrt(-1)==0, since the real part is 0. The most important effect of disallowing these casts would be to fix a host of bugs and wierd behaviour. All the A op= B operations involve a cast to A. If those nonsensical casts become illegal, the nonsensical op= operations become illegal automatically. Eg, ireal y; y *= y; // mathematically nonsense, y*y is real, so can't be stored in a pure imaginary type! There are a few segfault/ICE bugs (eg 718, 2839) which involve int/=complex, an operation which never makes any sense anyway. I think we're just making problems for ourselves by allowing these useless operations. I think they should be killed. Does anyone object? (If not, I'll create a patch to do it; it's not very difficult).Since you're looking into this already, I suggest we move for the kill and eliminate built-in complex. Andrei
Apr 30 2009
Robert Fraser:Ehhh.... why not leave complex and just kill imaginary? That'd solve most of the problems.You can't remove only half of a feature of the language, so I don't like this idea. I accept to remove them fully if their semantics can be fully replaced by the std lib. Otherwise just let Don fix the broken things. Bye, bearophile
Apr 30 2009
bearophile wrote:Robert Fraser:It's not necessarily "removing half a feature". Imaginary numbers aren't closed under many operations. The idea is that imaginary literals are turned into complex. So "ireal x = 10i;" becomes "creal x = 0 + 10i;". Since complex numbers are closed under all the builtin operators, it eliminates many of the problems (casts from complex to real). Putting it in a library eliminates the ability to use complex/imaginary literals (unless it's a runtime type).Ehhh.... why not leave complex and just kill imaginary? That'd solve most of the problems.You can't remove only half of a feature of the language, so I don't like this idea. I accept to remove them fully if their semantics can be fully replaced by the std lib. Otherwise just let Don fix the broken things. Bye, bearophile
Apr 30 2009
Robert Fraser wrote:Putting it in a library eliminates the ability to use complex/imaginary literals (unless it's a runtime type).Yah, but then I'm thinking: how many numeric literals are in a program at all? I think the vision of the mad scientist that uses one imaginary literal every five lines of code is quite unreal :o). Andrei
Apr 30 2009
Robert Fraser wrote:Ehhh.... why not leave complex and just kill imaginary? That'd solve most of the problems.The reasons for a separate imaginary type are listed in the D docs at <http://digitalmars.com/d/2.0/cppcomplex.html>, referencing William Kahan’s “Branch Cuts for Complex Elementary Functions, or Much Ado About Nothing’s Sign Bit”. It just doesn’t have to be a built-in type anymore. —Joel Salomon
Apr 30 2009
Andrei Alexandrescu wrote:Don wrote:I'd like to actually eliminate these operations from D1. Otherwise, I can't see the related D1 bugs ever getting fixed. Any code which relies on these operations is broken; I think there's an excellent chance that there isn't any code using it. Also, these operations would not be provided by a library class, so I think it's a useful intermediate step. We can't remove the complex types until we have a library solution.D currently allows some conversions between complex/imaginary types and real types, which are highly dubious. Given creal z, ireal y, these casts are legal: real x = cast(real)z; x = cast(real)y; // always sets x==0, regardless of the value of y. But I believe that should not be legal. For the first case, it should be written as: real x = z.re; (which is shorter and clearer), and the second case is probably a bug, and should be x = y.im; (unless the intention really was to set x=0!). By the same logic, we could have sqrt(-1)==0, since the real part is 0. The most important effect of disallowing these casts would be to fix a host of bugs and wierd behaviour. All the A op= B operations involve a cast to A. If those nonsensical casts become illegal, the nonsensical op= operations become illegal automatically. Eg, ireal y; y *= y; // mathematically nonsense, y*y is real, so can't be stored in a pure imaginary type! There are a few segfault/ICE bugs (eg 718, 2839) which involve int/=complex, an operation which never makes any sense anyway. I think we're just making problems for ourselves by allowing these useless operations. I think they should be killed. Does anyone object? (If not, I'll create a patch to do it; it's not very difficult).Since you're looking into this already, I suggest we move for the kill and eliminate built-in complex.
Apr 30 2009
Don wrote:I'd like to actually eliminate these operations from D1. Otherwise, I can't see the related D1 bugs ever getting fixed. Any code which relies on these operations is broken; I think there's an excellent chance that there isn't any code using it. Also, these operations would not be provided by a library class, so I think it's a useful intermediate step. We can't remove the complex types until we have a library solution.I think it's perfectly acceptable to not fix these in D1 and only address them in D2. There's lots of things in D1 that are only fixed in D2. Later, Brad
Apr 30 2009
Brad Roberts wrote:Don wrote:I think so many people are actually using D1, that ICE bugs really should get fixed.I'd like to actually eliminate these operations from D1. Otherwise, I can't see the related D1 bugs ever getting fixed. Any code which relies on these operations is broken; I think there's an excellent chance that there isn't any code using it. Also, these operations would not be provided by a library class, so I think it's a useful intermediate step. We can't remove the complex types until we have a library solution.I think it's perfectly acceptable to not fix these in D1 and only address them in D2. There's lots of things in D1 that are only fixed in D2.Later, Brad
Apr 30 2009
Don:I think we're just making problems for ourselves by allowing these useless operations. I think they should be killed. Does anyone object? (If not, I'll create a patch to do it; it's not very difficult).<I agree to disallow/fix those things. And thanks for your work! ------------- dsimcha:Show of hands, how many people here actually use D's complex numbers on a regular enough basis that you would miss them if they were removed from the core language completely?<D is in a flux state still, so I think very few engineer/scientists are using it (I am not using complex numbers). So probably the answers your will receive will not be enough to judge future true usages of the D language. A possible solution is to remove complex types now from D2 (moving them in Phobos and Tango), and later if enough people ask for them, to put them back into the built-ins. Are there problems in adding them back later if they are asked for and regarded as useful? ------------- Andrei Alexandrescu:Since you're looking into this already, I suggest we move for the kill and eliminate built-in complex.<Is the current semantics fully doable with std lib complex numbers? Bye, bearophile
Apr 30 2009
Don wrote:D currently allows some conversions between complex/imaginary types and real types, which are highly dubious. Given creal z, ireal y, these casts are legal: real x = cast(real)z; x = cast(real)y; // always sets x==0, regardless of the value of y. But I believe that should not be legal. For the first case, it should be written as: real x = z.re; (which is shorter and clearer), and the second case is probably a bug, and should be x = y.im; (unless the intention really was to set x=0!). By the same logic, we could have sqrt(-1)==0, since the real part is 0. The most important effect of disallowing these casts would be to fix a host of bugs and wierd behaviour. All the A op= B operations involve a cast to A. If those nonsensical casts become illegal, the nonsensical op= operations become illegal automatically. Eg, ireal y; y *= y; // mathematically nonsense, y*y is real, so can't be stored in a pure imaginary type! There are a few segfault/ICE bugs (eg 718, 2839) which involve int/=complex, an operation which never makes any sense anyway. I think we're just making problems for ourselves by allowing these useless operations. I think they should be killed. Does anyone object? (If not, I'll create a patch to do it; it's not very difficult).It might be a good idea to write in the docs why these operations are missing. Even better would of course be if the user got a message stating that this operation isn't implemented because it doesn't make mathematical sense. If the latter isn't done, then many people will just think there's something wrong with the compiler/language. Bad press we don't need.
Apr 30 2009
Georg Wrede wrote:Don wrote:I'll make sure the error messages are sensible.D currently allows some conversions between complex/imaginary types and real types, which are highly dubious. Given creal z, ireal y, these casts are legal: real x = cast(real)z; x = cast(real)y; // always sets x==0, regardless of the value of y. But I believe that should not be legal. For the first case, it should be written as: real x = z.re; (which is shorter and clearer), and the second case is probably a bug, and should be x = y.im; (unless the intention really was to set x=0!). By the same logic, we could have sqrt(-1)==0, since the real part is 0. The most important effect of disallowing these casts would be to fix a host of bugs and wierd behaviour. All the A op= B operations involve a cast to A. If those nonsensical casts become illegal, the nonsensical op= operations become illegal automatically. Eg, ireal y; y *= y; // mathematically nonsense, y*y is real, so can't be stored in a pure imaginary type! There are a few segfault/ICE bugs (eg 718, 2839) which involve int/=complex, an operation which never makes any sense anyway. I think we're just making problems for ourselves by allowing these useless operations. I think they should be killed. Does anyone object? (If not, I'll create a patch to do it; it's not very difficult).It might be a good idea to write in the docs why these operations are missing. Even better would of course be if the user got a message stating that this operation isn't implemented because it doesn't make mathematical sense.If the latter isn't done, then many people will just think there's something wrong with the compiler/language. Bad press we don't need.I don't think anyone expects to be able to divide an integer by an imaginary, and then assign it to an integer. I was astonished that the compiler accepted it.
Apr 30 2009
Don wrote:Georg Wrede wrote:Just goes to show you the average math knowledge. I never would have thought of omitting it either. :-)Don wrote:I'll make sure the error messages are sensible.D currently allows some conversions between complex/imaginary types and real types, which are highly dubious. Given creal z, ireal y, these casts are legal: real x = cast(real)z; x = cast(real)y; // always sets x==0, regardless of the value of y. But I believe that should not be legal. For the first case, it should be written as: real x = z.re; (which is shorter and clearer), and the second case is probably a bug, and should be x = y.im; (unless the intention really was to set x=0!). By the same logic, we could have sqrt(-1)==0, since the real part is 0. The most important effect of disallowing these casts would be to fix a host of bugs and wierd behaviour. All the A op= B operations involve a cast to A. If those nonsensical casts become illegal, the nonsensical op= operations become illegal automatically. Eg, ireal y; y *= y; // mathematically nonsense, y*y is real, so can't be stored in a pure imaginary type! There are a few segfault/ICE bugs (eg 718, 2839) which involve int/=complex, an operation which never makes any sense anyway. I think we're just making problems for ourselves by allowing these useless operations. I think they should be killed. Does anyone object? (If not, I'll create a patch to do it; it's not very difficult).It might be a good idea to write in the docs why these operations are missing. Even better would of course be if the user got a message stating that this operation isn't implemented because it doesn't make mathematical sense.If the latter isn't done, then many people will just think there's something wrong with the compiler/language. Bad press we don't need.I don't think anyone expects to be able to divide an integer by an imaginary, and then assign it to an integer. I was astonished that the compiler accepted it.
Apr 30 2009
Don wrote:I don't think anyone expects to be able to divide an integer by an imaginary, and then assign it to an integer. I was astonished that the compiler accepted it.There actually is a reason - completeness. Mathematically, there is a definite answer to it, so why not fill in all the entries for all the combinations?
May 03 2009
On Sun, May 3, 2009 at 2:35 AM, Walter Bright <newshound1 digitalmars.com> wrote:Don wrote:But the result of int divided by imaginary is pure imaginary. So I think Don's point was that you shouldn't be able to assign that back to an int. --bbI don't think anyone expects to be able to divide an integer by an imaginary, and then assign it to an integer. I was astonished that the compiler accepted it.There actually is a reason - completeness. Mathematically, there is a definite answer to it, so why not fill in all the entries for all the combinations?
May 03 2009
Walter Bright wrote:Don wrote:In the case complex = int/complex, there's no problem. It's the case int = int/complex that doesn't make sense. And that's fundamentally because cast(real)(2 + 3i) doesn't have a definite answer. There's no mathematical operation to convert a complex number to a real. Normally, to get a real result, you need to do something like multiplying by the complex conjugate. You CAN take the real part of a complex number, and you can also take the modulus (which makes a lot of sense if you're using polar represantation). Of course, cast() is not a mathematical operation, it's a D operation, so we can define it however we like. But defining it cast(real)z = z.re; is an arbitrary decision, which introduces lots of complexity to the language, and the many compiler bugs are a consequence. It's confusing for newbies (there's been questions on D.learn asking, "I can get the real part of a complex number with cast(real), but how do I get the imaginary part? cast(ireal) gives me an ireal, not a real!"). Since D supports the very nice .re syntax, there's really no reason to define cast(real) at all. z.re is better in 100% of use cases. There are *NO* use cases for cast(real); any use of cast(real) is a bug. We should kill it.I don't think anyone expects to be able to divide an integer by an imaginary, and then assign it to an integer. I was astonished that the compiler accepted it.There actually is a reason - completeness. Mathematically, there is a definite answer to it, so why not fill in all the entries for all the combinations?
May 04 2009
Don wrote:In the case complex = int/complex, there's no problem. It's the case int = int/complex that doesn't make sense. And that's fundamentally because cast(real)(2 + 3i) doesn't have a definite answer.Devil's advocate: one could argue it's the same as cast(int) of a float -- it returns the closest representable value, for some definition of "closest".
May 04 2009
Frits van Bommel wrote:Don wrote:Sure, you're at liberty to argue anything. But mathematicians don't do that. Nor should we. It's misleading, and just not helpful. BTW, another equally reasonable and equally unhelpful way you could define cast(real)(x + iy) is as sqrt(x*x - y*y). The most justifiable way to do it would be to say cast(real)(x+iy) is: if (y==0) return x; else throw(CastError); But again, it's just not helpful. Make it a compile-time error.In the case complex = int/complex, there's no problem. It's the case int = int/complex that doesn't make sense. And that's fundamentally because cast(real)(2 + 3i) doesn't have a definite answer.Devil's advocate: one could argue it's the same as cast(int) of a float -- it returns the closest representable value, for some definition of "closest".
May 04 2009
On Mon, 04 May 2009 10:56:41 +0200, Frits van Bommel wrote:Don wrote:Hmmm. not quite because we can not do ... int i = floatnum.integer; but we can do real r = complexnum.re; -- Derek Parnell Melbourne, Australia skype: derek.j.parnellIn the case complex = int/complex, there's no problem. It's the case int = int/complex that doesn't make sense. And that's fundamentally because cast(real)(2 + 3i) doesn't have a definite answer.Devil's advocate: one could argue it's the same as cast(int) of a float -- it returns the closest representable value, for some definition of "closest".
May 04 2009
Frits van Bommel Wrote:Don wrote:I consider this to be a much different case. Assuming the float to an int results on approximately the same number... And everyone knows what to expect. It's also possible to convert back to float and still have approximately the same number. For complex to int, the same things are not true. Conversion to float and then back to real can give a much different number... And not just for overflow, but normal uses of complex numbers. It's also unclear to mathematically inclined folk like me and Don what the conversion is supposed to do. A magnitude makes as much, if not more, sense. Adding to all this, there are easier, shorter, and clearer ways to do all of these conversions, and you _have_ to agree with Don ;)In the case complex = int/complex, there's no problem. It's the case int = int/complex that doesn't make sense. And that's fundamentally because cast(real)(2 + 3i) doesn't have a definite answer.Devil's advocate: one could argue it's the same as cast(int) of a float -- it returns the closest representable value, for some definition of "closest".
May 04 2009
Don Wrote:Since D supports the very nice .re syntax, there's really no reason to define cast(real) at all. z.re is better in 100% of use cases. There are *NO* use cases for cast(real); any use of cast(real) is a bug. We should kill it.I am with you. Making the language tidy is the way to go :-) Thank you for your work, and keep improving things when you can. Bye, bearophile
May 04 2009
Don wrote:Walter Bright wrote:Walter, could the error message then include "Please use z.re or z.im to get the parts, instead of a cast." or something. Otherwise we have to explain to all users separately what's going on, /and/ that the omission of implementing the cast in D isn't an omission.Don wrote:In the case complex = int/complex, there's no problem. It's the case int = int/complex that doesn't make sense. And that's fundamentally because cast(real)(2 + 3i) doesn't have a definite answer. There's no mathematical operation to convert a complex number to a real. Normally, to get a real result, you need to do something like multiplying by the complex conjugate. You CAN take the real part of a complex number, and you can also take the modulus (which makes a lot of sense if you're using polar represantation). Of course, cast() is not a mathematical operation, it's a D operation, so we can define it however we like. But defining it cast(real)z = z.re; is an arbitrary decision, which introduces lots of complexity to the language, and the many compiler bugs are a consequence. It's confusing for newbies (there's been questions on D.learn asking, "I can get the real part of a complex number with cast(real), but how do I get the imaginary part? cast(ireal) gives me an ireal, not a real!"). Since D supports the very nice .re syntax, there's really no reason to define cast(real) at all. z.re is better in 100% of use cases. There are *NO* use cases for cast(real); any use of cast(real) is a bug. We should kill it.I don't think anyone expects to be able to divide an integer by an imaginary, and then assign it to an integer. I was astonished that the compiler accepted it.There actually is a reason - completeness. Mathematically, there is a definite answer to it, so why not fill in all the entries for all the combinations?
May 04 2009
Georg Wrede wrote:Walter, could the error message then include "Please use z.re or z.im to get the parts, instead of a cast." or something. Otherwise we have to explain to all users separately what's going on, /and/ that the omission of implementing the cast in D isn't an omission.If we cut the limb, why first apply an ointment to it? Andrei
May 04 2009
On Mon, 04 May 2009 09:44:18 -0400, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:Georg Wrede wrote:I think the point is relevant to D1, where you can't really remove the limb, but you can apply make-up to make it look less deformed ;) -SteveWalter, could the error message then include "Please use z.re or z.im to get the parts, instead of a cast." or something. Otherwise we have to explain to all users separately what's going on, /and/ that the omission of implementing the cast in D isn't an omission.If we cut the limb, why first apply an ointment to it?
May 04 2009
On 04/30/2009 02:20 PM, Don wrote:D currently allows some conversions between complex/imaginary types and real types, which are highly dubious. Given creal z, ireal y, these casts are legal: real x = cast(real)z; x = cast(real)y; // always sets x==0, regardless of the value of y. But I believe that should not be legal. For the first case, it should be written as: real x = z.re; (which is shorter and clearer), and the second case is probably a bug, and should be x = y.im; (unless the intention really was to set x=0!). By the same logic, we could have sqrt(-1)==0, since the real part is 0. The most important effect of disallowing these casts would be to fix a host of bugs and wierd behaviour. All the A op= B operations involve a cast to A. If those nonsensical casts become illegal, the nonsensical op= operations become illegal automatically. Eg, ireal y; y *= y; // mathematically nonsense, y*y is real, so can't be stored in a pure imaginary type! There are a few segfault/ICE bugs (eg 718, 2839) which involve int/=complex, an operation which never makes any sense anyway. I think we're just making problems for ourselves by allowing these useless operations. I think they should be killed. Does anyone object? (If not, I'll create a patch to do it; it's not very difficult).Don, instead of this fix, could be at best phase everything built-in about complex out? Thanks, Andrei
Jun 12 2011
Andrei:Don, instead of this fix, could be at best phase everything built-in about complex out?Two usages of complex numbers in the RosettaCode site. Acommon place where you find complex numbers is to plot Mandelbrot/Julia sets: http://rosettacode.org/wiki/Mandelbrot_set#D import std.stdio, std.math; void main() { enum maxIter = 1000; foreach (y; -39 .. 39) { foreach (x; -39 .. 39) { auto c = y/40.0 - 0.5 + x/40.0i, z = 0.0 + 0.0i, i = 0; for (; i < maxIter && abs(z) < 4; i++) z = z ^^ 2 + c; } writeln(); } } Version using std.complex: import std.stdio, std.complex; void main() { enum maxIter = 1000; foreach (y; -39 .. 39) { foreach (x; -39 .. 39) { auto c = Complex!double(y/40.0 - 0.5, x/40.0), z = Complex!double(0, 0), i = 0; for (; i < maxIter && z.abs() < 4; i++) z = z ^^ 2 + c; } writeln(); } } I think it's worth adding to std.complex module few examples of usage, plus a complex() function so you are allowed to write (the imaginary part defaults to zero if the real part is set to zero): auto z = complex(5); Instead of: auto z = Complex!double(5, 0); complex(5) probably has to create a Complex!double and not a Complex!int (that is not even supported, std.complex.Complex support floating point values only). --------------------------- Another common usage of D complex numbers is to represent generic 2D points. http://rosettacode.org/wiki/Constrained_random_points_on_a_circle#D Original code (to plot some points in a circle): import std.stdio, std.random, std.math; void main() { char[31][31] table = ' '; foreach (i; 0 .. 100) { int x, y; do { x = uniform(-15, 16); y = uniform(-15, 16); } while(abs(12.5 - abs(x + y * 1i)) > 2.5); table[x + 15][y + 15] = '*'; } foreach (row; table) writeln(row); } Version using std.complex: import std.stdio, std.random, std.complex, std.math; void main() { char[31][31] table = ' '; foreach (i; 0 .. 100) { int x, y; do { x = uniform(-15, 16); y = uniform(-15, 16); } while(abs(12.5 - Complex!double(x, y).abs) > 2.5); table[x + 15][y + 15] = '*'; } foreach (row; table) writeln(row); } --------------------------- Regarding the printing of Complex values, this program: import std.stdio, std.complex; void main() { writeln(Complex!double(0, -1)); } Prints: 0-1i While Python prints the same complex number as:-1j Bye, bearophile0-1j
Jun 12 2011
On 12/06/2011 23:37, bearophile wrote:Andrei:I seemed to think the plan for complex numbers was to do what happened with associative arrays, that is, keep the language syntax, but have the feature implemented in the library. Is this not the case? -- Robert http://octarineparrot.com/Don, instead of this fix, could be at best phase everything built-in about complex out?Two usages of complex numbers in the RosettaCode site. Acommon place where you find complex numbers is to plot Mandelbrot/Julia sets: http://rosettacode.org/wiki/Mandelbrot_set#D import std.stdio, std.math; void main() { enum maxIter = 1000; foreach (y; -39 .. 39) { foreach (x; -39 .. 39) { auto c = y/40.0 - 0.5 + x/40.0i, z = 0.0 + 0.0i, i = 0; for (; i< maxIter&& abs(z)< 4; i++) z = z ^^ 2 + c; write(i == Version using std.complex: import std.stdio, std.complex; void main() { enum maxIter = 1000; foreach (y; -39 .. 39) { foreach (x; -39 .. 39) { auto c = Complex!double(y/40.0 - 0.5, x/40.0), z = Complex!double(0, 0), i = 0; for (; i< maxIter&& z.abs()< 4; i++) I think it's worth adding to std.complex module few examples of usage, plus a complex() function so you are allowed to write (the imaginary part defaults to zero if the real part is set to zero): auto z = complex(5);
Jun 13 2011
On Mon, 13 Jun 2011 12:36:27 +0100, Robert Clipsham wrote:On 12/06/2011 23:37, bearophile wrote:That was my understanding as well, which is why I never added a complex() helper function. It is, however, my humble opinion that we should just get rid of the complex literals. (Otherwise, std.complex would have to be moved into druntime.) -LarsAndrei:I seemed to think the plan for complex numbers was to do what happened with associative arrays, that is, keep the language syntax, but have the feature implemented in the library. Is this not the case?Don, instead of this fix, could be at best phase everything built-in about complex out?Two usages of complex numbers in the RosettaCode site. Acommon place where you find complex numbers is to plot Mandelbrot/Julia sets: http://rosettacode.org/wiki/Mandelbrot_set#D import std.stdio, std.math; void main() { enum maxIter = 1000; foreach (y; -39 .. 39) { foreach (x; -39 .. 39) { auto c = y/40.0 - 0.5 + x/40.0i, z = 0.0 + 0.0i, i = 0; for (; i< maxIter&& abs(z)< 4; i++) z = z ^^ 2 + c; write(i == Version using std.complex: import std.stdio, std.complex; void main() { enum maxIter = 1000; foreach (y; -39 .. 39) { foreach (x; -39 .. 39) { auto c = Complex!double(y/40.0 - 0.5, x/40.0), z = Complex!double(0, 0), i = 0; for (; i< maxIter&& z.abs()< 4; i++) z I think it's worth adding to std.complex module few examples of usage, plus a complex() function so you are allowed to write (the imaginary part defaults to zero if the real part is set to zero): auto z = complex(5);
Jun 13 2011
On 6/13/11 6:36 AM, Robert Clipsham wrote:I seemed to think the plan for complex numbers was to do what happened with associative arrays, that is, keep the language syntax, but have the feature implemented in the library. Is this not the case?No, the current vision is to completely replace complex with library artifacts. Walter wants to keep the "i" postfix as a hack, but I think that's completely unnecessary. A complex() convenience function should be useful. If anyone has the time, please create a pull request. It should never automatically create Complex with an integral type, as bearophile mentioned. For the rare cases where complex is needed with integrals, it should be fine to use Complex!int etc. directly. Andrei
Jun 13 2011
On Mon, 13 Jun 2011 08:36:32 -0500, Andrei Alexandrescu wrote:On 6/13/11 6:36 AM, Robert Clipsham wrote:Sure, I'll add complex(). Regarding Complex!int: I have explicitly restricted Complex to floating- point types. Here is a message I sent to the Phobos mailing list, explaining why: http://lists.puremagic.com/pipermail/phobos/2010-April/000286.html See also Don's reply to that message, it really drives the point home: http://lists.puremagic.com/pipermail/phobos/2010-April/000287.html -LarsI seemed to think the plan for complex numbers was to do what happened with associative arrays, that is, keep the language syntax, but have the feature implemented in the library. Is this not the case?No, the current vision is to completely replace complex with library artifacts. Walter wants to keep the "i" postfix as a hack, but I think that's completely unnecessary. A complex() convenience function should be useful. If anyone has the time, please create a pull request. It should never automatically create Complex with an integral type, as bearophile mentioned. For the rare cases where complex is needed with integrals, it should be fine to use Complex!int etc. directly.
Jun 13 2011
On Mon, 13 Jun 2011 14:51:52 +0000, Lars T. Kyllingstad wrote:On Mon, 13 Jun 2011 08:36:32 -0500, Andrei Alexandrescu wrote:As promised: https://github.com/D-Programming-Language/phobos/pull/103 -LarsA complex() convenience function should be useful. If anyone has the time, please create a pull request. [...]Sure, I'll add complex().
Jun 13 2011
Andrei:Walter wants to keep the "i" postfix as a hack, but I think that's completely unnecessary.Before deciding I'd like to know the rationale to keep it. In principle I like handy complex number literals. In practice I don't use them often enough... Another note: I'd like std.math.abs to perform what std.complex.Complex!T.abs does. So I will be able to use it functionally (currently std.math.abs is able to digest built-in complex numbers too): alias Complex!double C; C[] a = [C(1,2), C(2,4)]; auto m = map!abs(a); Bye, bearophile
Jun 13 2011