Re: floats default to NaN... why?
Jonathan M Davis wrote: No. You always have a bug if you don't initialize a variable to the value that it's supposed to be. It doesn't matter whether it's 0, NaN, 527.1209823, or whatever. All having a default value that you're more likely to use means is that you're less likely to have to explicitly initialize the variable. It has to be initialized to the correct value regardless. Yes, I'm in favor of default values. That's not my argument here. I'm saying it makes more sense to have the default values be _usable_ (for convenience) rather than designed to catch (**cause**) bugs. And if you're in the habit of always initializing variables and never relying on the defaults if you can help it, That seams like a very annoying habit requirement for a languages with a focus on "modern convenience". What's more bug prone, I think, is forcing developers to remember that unset floats (specifically) will cause bugs while it's neighboring int works perfectly without a explicit value. then the cases where variables weren't initialized to what they were supposed to be stand out more. Usable defaults don't need to stand out because they're usable and deterministic. If you want to make sure a constructor/method produces expected results, unittest it.. it makes more sense to catch errors at compile time anyways. D's approach is to say that it's _still_ a bug to not initialize a variable, since you almost always need to initialize a variable to something _other_ than a default. Not always, but that's besides the point. The point is that in the places where you do want zero values (Vector/Matrix/etc, Polygon structs, counters, etc..) it's better to have consistent expected behavior from the default value. Not some value that causes runtime bugs. I don't see how it's an issue, since you almost always need to initialize variables to something other than the default, and so leaving them as the default is almost always a bug. To me, it's not a huge issue, only an annoyance. However I wouldn't underestimate the impact of bad marketing. When people are trying out the language, and they read "variables are defaulted, not garbage" do you think they're going to expect ints and floats to work in different ways? And it doesn't cause bugs to default value types to zero. I have enough experience with C# to know that it doesn't. All it does is make the language more consistent. The only point of dispute that I see in general is whether it's better to rely on the default or to still explicitly initialize it when you actually want the default. This sounds like an argument for C++. Explicit declaration isn't a guard against bugs, you'll still be hunting through code if something is incorrectly set. The fact of the matter is default initialization _does_ happen in code, no matter how philosophically correct "always explicitly define value" might be. Unless that's enforced, it can and should be expected to happen. That given, it's more convenient to have consistent value type behavior. Float is a Value type and shouldn't be subjective to the security concerns of Reference types. Regardless, the _entire_ reason for default-initialization in D revolves around making buggy initializations deterministic and more detectable. The same way string, and int are defaulted to usable values, float should be as well. Catching code that works with null pointers is one thing. Working with a value type without requiring the programmer have deeper knowledge about D's asymmetrical features is another. If D doesn't accommodate entering Laymen, how does it expect to gain popularity in any major way? Efficiency puts D on the map, convenience is what brings the tourists. I'm not trying to convince you that the sky is falling because I disagree with D's direction with floats.. just if the goal is to increase D's popularity, little things may turn heads away quicker than you think. My original post was inspired by me showing my D code to another C# guy earlier, and coming up with poor explanations as to why floats where required to be defaulted in my math lib. His reaction what along the lines of my first post.
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 06:43:11 UTC, Manfred Nowak wrote: F i L wrote: It sounds like circular reasoning. Several considerations pressed the design into the current form: 1) always changing output on unchanged input is hard to debug 2) GC needs to be saved from garbage, that looks like pointers 3) missed explicit initializations should not create syntax errors 4) use hardware signalling to overcome some of the limitations impressed by 3). 5) more??? For me the only questionable point is numer three. -manfred 1) Good argument. 2) Don't know enough about the GC. Can't comment. 3) I agree. I just disagree with how they are expected to be used without explicit definition. 4) I have no idea what you just said... :) 5) profit??
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 06:29:40 UTC, Ali Çehreli wrote: On 04/13/2012 09:00 PM, F i L wrote: > default is NaN Just to complete the picture, character types have invalid initial values as well: 0xFF, 0x, and 0x for char, wchar, and dchar, respectively. Ali That's interesting, but what effect does appending an invalid char to a valid one have? Does the resulting string end up being "NaS" (Not a String)? Cause if not, I'm not sure that's a fair comparison.
Re: floats default to NaN... why?
On Saturday, April 14, 2012 09:45:57 F i L wrote: > If D doesn't accommodate entering Laymen, how does it expect to > gain popularity in any major way? Efficiency puts D on the map, > convenience is what brings the tourists. I believe that you are the first person that I have ever heard complain that D tries to default to error values. I think that some have asked why the types default to what they default to, but it's not something that people normally complain about. I've explained the reasoning behind it. You can like it or not, but as far as I can tell, this is a complete non-issue. - Jonathan M Davis
Re: floats default to NaN... why?
On Saturday, April 14, 2012 09:58:42 F i L wrote: > On Saturday, 14 April 2012 at 06:29:40 UTC, Ali Çehreli wrote: > > On 04/13/2012 09:00 PM, F i L wrote: > > > default is NaN > > > > Just to complete the picture, character types have invalid > > initial values as well: 0xFF, 0x, and 0x for char, > > wchar, and dchar, respectively. > > > > Ali > > That's interesting, but what effect does appending an invalid > char to a valid one have? Does the resulting string end up being > "NaS" (Not a String)? Cause if not, I'm not sure that's a fair > comparison. You can't append a char to a char. You can append them to strings, but not each other. Appending an invalid char results in a string with an invalid char. It won't blow up on its own. But any function which attempts to decode the string (which includes the vast majority of functions which would be called on a string) would result in a UTFException. So, you'll generally know that you have a bad string very quickly. - Jonathan M Davis
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 07:59:25 UTC, Jonathan M Davis wrote: On Saturday, April 14, 2012 09:45:57 F i L wrote: If D doesn't accommodate entering Laymen, how does it expect to gain popularity in any major way? Efficiency puts D on the map, convenience is what brings the tourists. I believe that you are the first person that I have ever heard complain that D tries to default to error values. I think that some have asked why the types default to what they default to, but it's not something that people normally complain about. I've explained the reasoning behind it. You can like it or not, but as far as I can tell, this is a complete non-issue. Well my testimonial evidence against yours, eh? :) I'm not trying to get under anyone's skin here. You've explained the logic behind the decision and I think I've made some valid points against that logic. You obviously don't feel like arguing the point further, so I'll just leave it at that.
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 07:52:51 UTC, F i L wrote: On Saturday, 14 April 2012 at 06:43:11 UTC, Manfred Nowak wrote: F i L wrote: 4) use hardware signalling to overcome some of the limitations impressed by 3). 4) I have no idea what you just said... :) On Saturday, 14 April 2012 at 07:58:44 UTC, F i L wrote: That's interesting, but what effect does appending an invalid char to a valid one have? Does the resulting string end up being "NaS" (Not a String)? Cause if not, I'm not sure that's a fair comparison. The initialization values chosen are also determined by the underlying hardware implementation of the type. Signalling NANs (http://en.wikipedia.org/wiki/NaN#Signaling_NaN) can be used with floats because they are implemented by the CPU, but in the case of integers or strings their aren't really equivalent values. On Saturday, 14 April 2012 at 07:45:58 UTC, F i L wrote: My original post was inspired by me showing my D code to another C# guy earlier, and coming up with poor explanations as to why floats where required to be defaulted in my math lib. His reaction what along the lines of my first post. I think the correct mindset when working in D is to think that "all variables should be initialized" and if you get incorrect calculations with zero values, division by zero errors or nan errors the most likely mistake is often that this guideline was not followed.
Re: floats default to NaN... why?
Am 14.04.2012 07:48, schrieb F i L: On Saturday, 14 April 2012 at 05:19:38 UTC, dennis luehring wrote: Am 14.04.2012 06:00, schrieb F i L: struct Foo { int x, y;// ready for use. float z, w; // messes things up. float r = 0; // almost always... } how often in your code is 0 or 0.0 the real starting point? i can't think of any situation except counters or something where 0 is a proper start - and float 0.0 is in very very few cases a normal start - so whats your point? Every place that a structure property is designed to be mutated externally. Almost all Math structures, for instance. if a float or double is initalized with nan - all operations on them will result to nan - that is a very good sign for missing "proper" initialisation what does make float default to 0.0 better - does it just feel better?
"shared" status
What is the status of "shared" types ? I try it with gdmd v4.6.3 And I not get any warring/error when I do anything over a shared variable without using atomicOp. It's normal ? shared ushort ram[ram_size]; ram[i] = cast(ushort) (bytes[0] | bytes[1] << 8); -- I'm afraid that I have a blog: http://zardoz.es
Re: floats default to NaN... why?
On 14/04/12 09:45, F i L wrote: Jonathan M Davis wrote: No. You always have a bug if you don't initialize a variable to the value that it's supposed to be. It doesn't matter whether it's 0, NaN, 527.1209823, or whatever. All having a default value that you're more likely to use means is that you're less likely to have to explicitly initialize the variable. It has to be initialized to the correct value regardless. Yes, I'm in favor of default values. That's not my argument here. I'm saying it makes more sense to have the default values be _usable_ (for convenience) rather than designed to catch (**cause**) bugs. Why would a compiler set `real' to 0.0 rather then 1.0, Pi, ? The more convenient default set certainly depends on the underlying mathematics, and a compiler cannot (yet) understand the encoded mathematics. NaN is certainly the certainly the very choice as whatever the involved mathematics, they will blow up sooner or later. And, from a practical point of view, blowing up is easy to trace.
Re: floats default to NaN... why?
F i L: So basically, it's for debugging? To avoid bugs it's useful for all variables to be initialized before use (maybe with an explicit annotation for the uncommon cases where you want to use uninitialized memory, like: http://research.swtch.com/sparse ). Having a variable not initialized is a common source of bugs. C# solves this requiring explicit initialization all variables before use. Walter doesn't believe that flow analysis is flexible enough in a system language like D (or he doesn't want to implement it) so he has not used this idea in D. So D uses a different worse strategy, it initializes the variables to something unusable, so if you try to use them, your program fails clearly. The idea of setting the variables to something useful, like setting initialized chars to 'a' and floating point values to 0.0 looks handy, but on the long run it's not an improvement. You sometimes don't initialize a char variable because you are fine for it to be 'a', and some other times you don't set it just because you forget to initialize it. The compiler can't tell apart the two cases, and this is may be a bug in your code. In practice I think having FP variables initialized to NaN has not avoided me significant bugs in the last years. On the other hand I have ported some C code that uses global floating point arrays/variables to D, and I have had to remove some bugs caused by the assumption in the C code that those global FP variables are initialized to zero, that's false in D. Another source of troubles is large fixed-sized FP global arrays, that inflate the binary a *lot*. You have to remember to initialize them to zero explicitly: double[100_000] foo; // bad, inflates binary. double[100_000] bar = 0.0; // good. void main() {} In D I'd like the solution used by C# + an annotation to not initialize a variable or array. Bye, bearophile
Re: floats default to NaN... why?
On 4/14/12, bearophile wrote: > Having a variable not initialized is a common source of bugs. I'm going to argue that this was true for C/C++ but is much less true for D. One benefit of having integrals initialized to 0 is that you now have a defined default that you can rely on (just as you can rely on pointers being null by default). Personally I find this to be a big win in productivity. If the language/runtime does something defined for me then I can focus on more important things. But NaN might be a good thing for all I know.. I rarely use floating-point so I'll stay out of that, but I'd like to have this fixed: http://d.puremagic.com/issues/show_bug.cgi?id=6303
Re: floats default to NaN... why?
Jerome BENOIT wrote: Why would a compiler set `real' to 0.0 rather then 1.0, Pi, ? Because 0.0 is the "lowest" (smallest, starting point, etc..) numerical value. Pi is the corner case and obviously has to be explicitly set. If you want to take this further, chars could even be initialized to spaces or newlines or something similar. Pointers/references need to be defaulted to null because they absolutely must equal an explicit value before use. Value types don't share this limitation. The more convenient default set certainly depends on the underlying mathematics, and a compiler cannot (yet) understand the encoded mathematics. NaN is certainly the certainly the very choice as whatever the involved mathematics, they will blow up sooner or later. And, from a practical point of view, blowing up is easy to trace. Zero is just as easy for the runtime/compiler to default to; and bugs can be introduce anywhere in the code, not just definition. We have good ways of catching these bugs in D with unittests already.
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 10:38:45 UTC, Silveri wrote: On Saturday, 14 April 2012 at 07:52:51 UTC, F i L wrote: On Saturday, 14 April 2012 at 06:43:11 UTC, Manfred Nowak wrote: F i L wrote: 4) use hardware signalling to overcome some of the limitations impressed by 3). 4) I have no idea what you just said... :) On Saturday, 14 April 2012 at 07:58:44 UTC, F i L wrote: That's interesting, but what effect does appending an invalid char to a valid one have? Does the resulting string end up being "NaS" (Not a String)? Cause if not, I'm not sure that's a fair comparison. The initialization values chosen are also determined by the underlying hardware implementation of the type. Signalling NANs (http://en.wikipedia.org/wiki/NaN#Signaling_NaN) can be used with floats because they are implemented by the CPU, but in the case of integers or strings their aren't really equivalent values. I'm sure the hardware can just as easily signal zeros. On Saturday, 14 April 2012 at 07:45:58 UTC, F i L wrote: My original post was inspired by me showing my D code to another C# guy earlier, and coming up with poor explanations as to why floats where required to be defaulted in my math lib. His reaction what along the lines of my first post. I think the correct mindset when working in D is to think that "all variables should be initialized" and if you get incorrect calculations with zero values, division by zero errors or nan errors the most likely mistake is often that this guideline was not followed. Like I said before, this is backwards thinking. At the end of the day, you _can_ use default values in D. Given that ints are defaulted to usable values, FP Values should be as well for the sake of consistency and convenience. You can't force new D programmers to follow a 'guidline' no matter how loudly the documentation shouts it (which is barely does at this point), so said guideline is not a dependable practice all D will follow (unless it's statically enforced)... nor _should_ the learning curve be steepened by enforcing awareness of this idiosyncrasy. The correct mindset from the compilers perspective should be: "people create variables to use them. What do they want if they didn't specify a value?" therefor our mindset can be: "I defined a variable to use. Should be zero so I don't need to set it."
Re: floats default to NaN... why?
dennis luehring wrote: what does make float default to 0.0 better - does it just feel better? Not just. It's consistent with Int types, therefor easier for newbs to pick up since all numeric value types behave the same. I even think char should default to a usable value as well. Most likely a space character. But that's another point.
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 12:48:01 UTC, Andrej Mitrovic wrote: On 4/14/12, bearophile wrote: Having a variable not initialized is a common source of bugs. I'm going to argue that this was true for C/C++ but is much less true for D. One benefit of having integrals initialized to 0 is that you now have a defined default that you can rely on (just as you can rely on pointers being null by default). Personally I find this to be a big win in productivity. If the language/runtime does something defined for me then I can focus on more important things. Amen! This is exactly what I'm trying to get at. The compiler provides defaults as a convince feature (mostly) so that there's no garbage and so values are reliable. It's incredibly inconvenient at that point to have to remember to always explicitly init one specific type.. This feels very natural in C#.
Re: floats default to NaN... why?
On 4/14/12, F i L wrote: > This is exactly what I'm trying to get at. Anyway it's not all bad news since we can use a workaround: struct Float { float payload = 0.0; alias payload this; } void main() { Float x; // acts as a float, is initialized to 0.0 } Not pretty, but it comes in handy.
Re: floats default to NaN... why?
On 14/04/12 16:47, F i L wrote: Jerome BENOIT wrote: Why would a compiler set `real' to 0.0 rather then 1.0, Pi, ? Because 0.0 is the "lowest" (smallest, starting point, etc..) quid -infinity ? numerical value. Pi is the corner case and obviously has to be explicitly set. If you want to take this further, chars could even be initialized to spaces or newlines or something similar. Pointers/references need to be defaulted to null because they absolutely must equal an explicit value before use. Value types don't share this limitation. CHAR set are bounded, `real' are not. The more convenient default set certainly depends on the underlying mathematics, and a compiler cannot (yet) understand the encoded mathematics. NaN is certainly the certainly the very choice as whatever the involved mathematics, they will blow up sooner or later. And, from a practical point of view, blowing up is easy to trace. Zero is just as easy for the runtime/compiler to default to; Fortran age is over. D compiler contains a lot of features that are not easy to set up by the compiler BUT meant for easing coding. and bugs can be introduce anywhere in the code, not just definition. so the NaN approach discard one source of error. We have good ways of catching these bugs in D with unittests already. Zero may give a value that sounds reasonable, NaN will give a NaN value ... which is not reasonable: this is NaN blow up and it can been seen right the way. Note that the NaN approach is used in some numerical libraries as CLN.
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 15:44:46 UTC, Jerome BENOIT wrote: On 14/04/12 16:47, F i L wrote: Jerome BENOIT wrote: Why would a compiler set `real' to 0.0 rather then 1.0, Pi, ? Because 0.0 is the "lowest" (smallest, starting point, etc..) quid -infinity ? The concept of zero is less meaningful than -infinity. Zero is the logical starting place because zero represents nothing (mathematically), which is inline with how pointers behave (only applicable to memory, not scale). numerical value. Pi is the corner case and obviously has to be explicitly set. If you want to take this further, chars could even be initialized to spaces or newlines or something similar. Pointers/references need to be defaulted to null because they absolutely must equal an explicit value before use. Value types don't share this limitation. CHAR set are bounded, `real' are not. Good point, I'm not so convinced char should default to " ". I think there are arguments either way, I haven't given it much thought. The more convenient default set certainly depends on the underlying mathematics, and a compiler cannot (yet) understand the encoded mathematics. NaN is certainly the certainly the very choice as whatever the involved mathematics, they will blow up sooner or later. And, from a practical point of view, blowing up is easy to trace. Zero is just as easy for the runtime/compiler to default to; Fortran age is over. D compiler contains a lot of features that are not easy to set up by the compiler BUT meant for easing coding. and bugs can be introduce anywhere in the code, not just definition. so the NaN approach discard one source of error. Sure, the question then becomes "does catching bugs introduced by inaccurately defining a variable outweigh the price of inconsistency and learning curve." My opinion is No, expected behavior is more important. Especially when I'm not sure I've ever heard of someone in C# having bugs that would have been helped by defaulting to NaN. I mean really, how does: float x; // NaN ... x = incorrectValue; ... foo(x); // first time x is used differ from: float x = incorrectValue; ... foo(x); in any meaning full way? Except that in this one case: float x; // NaN ... foo(x); // uses x, resulting in NaNs ... x = foo(x); // sets after first time x is used you'll get a "more meaningful" error message, which, assuming you didn't just write a ton of FP code, you'd be able to trace to it's source faster. It just isn't enough to justify defaulting to NaN, IMO. I even think the process of hunting down bugs is more straight forward when defaulting to zero, because every numerical bug is pursued the same way, regardless of type. You don't have to remember that FP specifically causes this issues in only some cases.
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 15:35:13 UTC, Andrej Mitrovic wrote: On 4/14/12, F i L wrote: This is exactly what I'm trying to get at. Anyway it's not all bad news since we can use a workaround: struct Float { float payload = 0.0; alias payload this; } void main() { Float x; // acts as a float, is initialized to 0.0 } Not pretty, but it comes in handy. Lol, that's kinda an interesting idea: struct var(T, T def) { T payload = def; alias payload this; } alias var!(float, 0.0f) Float; alias var!(double, 0.0) Double; alias var!(real, 0.0) Real; alias var!(char, ' ') Char; void main() { Float f; assert(f == 0.0f); } a Hack though, since it doesn't work with 'auto'. I still think it should be the other way around, and this should be used to Default to NaN.
Re: floats default to NaN... why?
On 4/14/12, F i L wrote: > a Hack though, since it doesn't work with 'auto'. What do you mean?
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 17:30:19 UTC, Andrej Mitrovic wrote: On 4/14/12, F i L wrote: a Hack though, since it doesn't work with 'auto'. What do you mean? Only that: auto f = 1.0f; // is float not Float
Re: floats default to NaN... why?
On 4/14/12, F i L wrote: > auto f = 1.0f; // is float not Float UFCS in 2.059 to the rescue: struct Float { float payload = 0.0; alias payload this; } @property Float f(float val) { return Float(val); } void main() { auto f = 1.0.f; }
Re: floats default to NaN... why?
On 14/04/12 18:38, F i L wrote: On Saturday, 14 April 2012 at 15:44:46 UTC, Jerome BENOIT wrote: On 14/04/12 16:47, F i L wrote: Jerome BENOIT wrote: Why would a compiler set `real' to 0.0 rather then 1.0, Pi, ? Because 0.0 is the "lowest" (smallest, starting point, etc..) quid -infinity ? The concept of zero is less meaningful than -infinity. Zero is the logical starting place because zero represents nothing (mathematically) zero is not nothing in mathematics, on the contrary ! 0 + x = 0 // neutral for addition 0 * x = 0 // absorbing for multiplication 0 / x = 0 if (x <> 0) // idem | x / 0 | = infinity if (x <> 0) 0 / 0 = NaN // undefined , which is inline with how pointers behave (only applicable to memory, not scale). pointer value are also bounded. numerical value. Pi is the corner case and obviously has to be explicitly set. If you want to take this further, chars could even be initialized to spaces or newlines or something similar. Pointers/references need to be defaulted to null because they absolutely must equal an explicit value before use. Value types don't share this limitation. CHAR set are bounded, `real' are not. Good point, I'm not so convinced char should default to " ". I think there are arguments either way, I haven't given it much thought. The more convenient default set certainly depends on the underlying mathematics, and a compiler cannot (yet) understand the encoded mathematics. NaN is certainly the certainly the very choice as whatever the involved mathematics, they will blow up sooner or later. And, from a practical point of view, blowing up is easy to trace. Zero is just as easy for the runtime/compiler to default to; Fortran age is over. D compiler contains a lot of features that are not easy to set up by the compiler BUT meant for easing coding. and bugs can be introduce anywhere in the code, not just definition. so the NaN approach discard one source of error. Sure, the question then becomes "does catching bugs introduced by inaccurately defining a variable outweigh the price of inconsistency and learning curve." My opinion is No, expected behavior is more important. From a numerical point of view, zero is not a good default (see above), and as such setting 0.0 as default for real is not an expected behaviour. Considering the NaN blow up behaviour, for a numerical folk the expected behaviour is certainly setting NaN as default for real. Real number are not meant here for coders, but for numerical folks: D applies here a rule gain along experiences from numerical people. So your opinion is good, but you misplaced the inconsistency: 0 is inaccurate here and NaN is accurate, not the contrary. Especially when I'm not sure I've ever heard of someone in C# having bugs that would have been helped by defaulting to NaN. I mean really, how does: float x; // NaN ... x = incorrectValue; ... foo(x); // first time x is used differ from: float x = incorrectValue; ... foo(x); in any meaning full way? Except that in this one case: float x; // NaN ... foo(x); // uses x, resulting in NaNs ... x = foo(x); // sets after first time x is used you'll get a "more meaningful" error message, which, assuming you didn't just write a ton of FP code, you'd be able to trace to it's source faster. It just isn't enough to justify defaulting to NaN, IMO. I even think the process of hunting down bugs is more straight forward when defaulting to zero, because every numerical bug is pursued the same way, regardless of type. You don't have to remember that FP specifically causes this issues in only some cases. For numerical works, because 0 behaves nicely most of the time, non properly initialized variables may not detected because the output data can sound resoneable; on the other hand, because NaN blows up, such detection is straight forward: the output will be a NaN output which will jump to your face very quickly. This is a numerical issue, not a coding language issue. Personally in my C code, I have taken the habit to initialise real numbers (doubles) with NaN: in the GSL library there is a ready to use macro: GSL_NAN. (Concerning, integers I used extreme value as INT_MIN, INT_MAX, SIZE_MAX. ...). I would even say that D may go further by setting a kind of NaN for integers (and for chars).
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 18:02:57 UTC, Andrej Mitrovic wrote: On 4/14/12, F i L wrote: auto f = 1.0f; // is float not Float UFCS in 2.059 to the rescue: struct Float { float payload = 0.0; alias payload this; } @property Float f(float val) { return Float(val); } void main() { auto f = 1.0.f; } You're a scholar and and gentlemen!
Calling delegate properties without parens
I have following code: import std.array, std.range, std.stdio; struct CommonInputRange(E) { @property bool delegate() empty; @property E delegate() front; void delegate() popFront; } void main(string[] args) { alias CommonInputRange!dchar DCRange; static assert(isInputRange!DCRange); DCRange dc; auto dcr = "abcdefg"; auto t = dcr.takeExactly(3); dc.empty = &t.empty; dc.front = &t.front; dc.popFront = &t.popFront; for ( ; !dc.empty(); dc.popFront()) writeln(dc.front()); } As you can see in the for loop, range primitives must be called using parens (), otherwise they don't work. Do you know if there are plans to implement @property for delegates and function pointers?
Re: floats default to NaN... why?
On Saturday, 14 April 2012 at 18:07:41 UTC, Jerome BENOIT wrote: On 14/04/12 18:38, F i L wrote: On Saturday, 14 April 2012 at 15:44:46 UTC, Jerome BENOIT wrote: On 14/04/12 16:47, F i L wrote: Jerome BENOIT wrote: Why would a compiler set `real' to 0.0 rather then 1.0, Pi, ? Because 0.0 is the "lowest" (smallest, starting point, etc..) quid -infinity ? The concept of zero is less meaningful than -infinity. Zero is the logical starting place because zero represents nothing (mathematically) zero is not nothing in mathematics, on the contrary ! 0 + x = 0 // neutral for addition 0 * x = 0 // absorbing for multiplication 0 / x = 0 if (x <> 0) // idem | x / 0 | = infinity if (x <> 0) Just because mathematical equations behave differently with zero doesn't change the fact that zero _conceptually_ represents "nothing" It's default for practical reason. Not for mathematics sake, but for the sake of convenience. We don't all study higher mathematics but we're all taught to count since we where toddlers. Zero makes sense as the default, and is compounded by the fact that Int *must* be zero. 0 / 0 = NaN // undefined Great! Yet another reason to default to zero. That way, "0 / 0" bugs have a very distinct fingerprint. , which is inline with how pointers behave (only applicable to memory, not scale). pointer value are also bounded. I don't see how that's relevant. Considering the NaN blow up behaviour, for a numerical folk the expected behaviour is certainly setting NaN as default for real. Real number are not meant here for coders, but for numerical folks: Of course FP numbers are meant for coders... they're in a programming language. They are used by coders, and not every coder that uses FP math *has* to be well trained in the finer points of mathematics simply to use a number that can represent fractions in a conceptually practical way. D applies here a rule gain along experiences from numerical people. I'm sorry I can't hear you over the sound of how popular Java and C# are. Convenience is about productivity, and that's largely influence by how much prior knowledge someone needs before being able to understand a features behavior. (ps. if you're going to use Argumentum ad Verecundiam, I get to use Argumentum ad Populum). For numerical works, because 0 behaves nicely most of the time, non properly initialized variables may not detected because the output data can sound resoneable; on the other hand, because NaN blows up, such detection is straight forward: the output will be a NaN output which will jump to your face very quickly. I gave examples which address this. This behavior is only [debatably] beneficial in corner cases on FP numbers specifically. I don't think that sufficient justification in light of reasons I give above. This is a numerical issue, not a coding language issue. No, it's both. We're not Theoretical physicists we're Software Engineers writing a very broad scope of different programs. Personally in my C code, I have taken the habit to initialise real numbers (doubles) with NaN: in the GSL library there is a ready to use macro: GSL_NAN. (Concerning, integers I used extreme value as INT_MIN, INT_MAX, SIZE_MAX. ...). Only useful because C defaults to garbage. I would even say that D may go further by setting a kind of NaN for integers (and for chars). You may get your with if Arm64 takes over.
Re: floats default to NaN... why?
On 4/14/12, Jerome BENOIT wrote: > I would even say that D may go further by setting a kind of NaN for integers. That's never going to happen.
Re: floats default to NaN... why?
F i L wrote: > You can't force new D programmers to follow a 'guidline' By exposing a syntax error for every missed explicit initialization the current guideline would be changed into an insurmountable barrier, forcing every "new D programmers to follow" the 'guidline'. -manfred
D 50% slower than C++. What I'm doing wrong?
I have this simple binary arithmetic coder in C++ by Mahoney and translated to D by Maffi. I added "notrow", "final" and "pure" and "GC.disable" where it was possible, but that didn't made much difference. Adding "const" to the Predictor.p() (as in the C++ version) gave 3% higher performance. Here the two versions: http://mattmahoney.net/dc/ <-- original zip http://pastebin.com/55x9dT9C <-- Original C++ version. http://pastebin.com/TYT7XdwX <-- Modified D translation. The problem is that the D version is 50% slower: test.fpaq0 (16562521 bytes) -> test.bmp (33159254 bytes) Lang| Comp | Binary size | Time (lower is better) C++ (g++) - 13kb - 2.42s (100%) -O3 -s D(DMD) - 230kb - 4.46s (184%) -O -release -inline D(GDC) -1322kb - 3.69s (152%) -O3 -frelease -s The only diference I could see between the C++ and D versions is that C++ has hints to the compiler about which functions to inline, and I could't find anything similar in D. So I manually inlined the encode and decode functions: http://pastebin.com/N4nuyVMh - Manual inline D(DMD) - 228kb - 3.70s (153%) -O -release -inline D(GDC) -1318kb - 3.50s (144%) -O3 -frelease -s Still, the D version is slower. What makes this speed diference? Is there any way to side-step this? Note that this simple C++ version can be made more than 2 times faster with algoritimical and io optimizations, (ab)using templates, etc. So I'm not asking for generic speed optimizations, but only things that may make the D code "more equal" to the C++ code.
A "general" tag
Hi, I try to translate a script I wrote in Fantom [www.fantom.org]. In my script, I have a type "Tag" defined as a triple of: - String (the name of the tag), - Type (the type of the tag: could be Str, Date, Int, etc.) - Obj (the value of the tag; Fantom has Objects of Top-Class hierachy). (normally the tag has Type = Obj.Type, but you can manually set). For example, you could have: (name, Str#, "John") or (date, Date#, 2011-09-02) (# is the Fantom way for specifying type: Str# is the sys::Str type) Is there any way for emulating this? My main trouble is how to define Type and Object in D. Thanks in advance, Xan. PS: Please, be patient, I'm a newbee.
Re: floats default to NaN... why?
On 14/04/12 16:52, F i L wrote: The initialization values chosen are also determined by the underlying hardware implementation of the type. Signalling NANs (http://en.wikipedia.org/wiki/NaN#Signaling_NaN) can be used with floats because they are implemented by the CPU, but in the case of integers or strings their aren't really equivalent values. I'm sure the hardware can just as easily signal zeros. The point is not that the hardware can't deal with floats initialized to zero. The point is that the hardware CAN'T support an integer equivalent of NaN. If it did, D would surely use it. Like I said before, this is backwards thinking. At the end of the day, you _can_ use default values in D. Given that ints are defaulted to usable values, FP Values should be as well for the sake of consistency and convenience. Speaking as a new user (well, -ish), my understanding of D is that its design philosophy is that _the easy thing to do should be the safe thing to do_, and this concept is pervasive throughout the design of the whole language. So, ideally (as bearophile says) you'd compel the programmer to explicitly initialize variables before using them, or explicitly specify that they are not being initialized deliberately. Enforcing that may be tricky (most likely not impossible, but tricky, and there are bigger problems to solve for now), so the next best thing is to default-initialize variables to something that will scream at you "THIS IS WRONG!!" when the program runs, and so force you to correct the error. For floats, that means NaN. For ints, the best thing you can do is zero. It's a consistent decision -- not consistent as you frame it, but consistent with the language design philosophy. You can't force new D programmers to follow a 'guidline' no matter how loudly the documentation shouts it No, but you can drop very strong hints as to good practice. Relying on default values for variables is bad programming. The fact that it is possible with integers is a design fault forced on the language by hardware constraints. As a language designer, do you compound the fault by making floats also init to 0 or do you enforce good practice in a way which will probably make the user reconsider any assumptions they may have made for ints? Novice programmers need support, but support should not extend to pandering to bad habits which they would be better off unlearning (or never learning in the first place).
Re: floats default to NaN... why?
On 14/04/12 20:51, F i L wrote: On Saturday, 14 April 2012 at 18:07:41 UTC, Jerome BENOIT wrote: On 14/04/12 18:38, F i L wrote: On Saturday, 14 April 2012 at 15:44:46 UTC, Jerome BENOIT wrote: On 14/04/12 16:47, F i L wrote: Jerome BENOIT wrote: Why would a compiler set `real' to 0.0 rather then 1.0, Pi, ? Because 0.0 is the "lowest" (smallest, starting point, etc..) quid -infinity ? The concept of zero is less meaningful than -infinity. Zero is the logical starting place because zero represents nothing (mathematically) zero is not nothing in mathematics, on the contrary ! 0 + x = 0 // neutral for addition 0 * x = 0 // absorbing for multiplication 0 / x = 0 if (x <> 0) // idem | x / 0 | = infinity if (x <> 0) Just because mathematical equations behave differently with zero doesn't change the fact that zero _conceptually_ represents "nothing" You are totally wrong: here we are dealing with key concept of the group theory. It's default for practical reason. Not for mathematics sake, but for the sake of convenience. We don't all study higher mathematics but we're all taught to count since we where toddlers. Zero makes sense as the default, and is compounded by the fact that Int *must* be zero. The sake of convenience here is numerical practice, not coding practice: this is the point: from numerical folks, zero is a very bad choice; NaN is a very good one. 0 / 0 = NaN // undefined Great! Yet another reason to default to zero. That way, "0 / 0" bugs have a very distinct fingerprint. While the other (which are by far more likely) are bypassed: here you are making a point against yourself: NaN + x = NaN NaN * x = NaN x / NaN = NaN NaN / x = NaN , which is inline with how pointers behave (only applicable to memory, not scale). pointer value are also bounded. I don't see how that's relevant. Because then zero is a meaningful default for pointers. Considering the NaN blow up behaviour, for a numerical folk the expected behaviour is certainly setting NaN as default for real. Real number are not meant here for coders, but for numerical folks: Of course FP numbers are meant for coders... they're in a programming language. They are used by coders, and not every coder that uses FP math *has* to be well trained in the finer points of mathematics simply to use a number that can represent fractions in a conceptually practical way. The above is not finer points, but basic ones. Otherwise, float and double are rather integers than by fractions. D applies here a rule gain along experiences from numerical people. I'm sorry I can't hear you over the sound of how popular Java and C# are. Sorry, I can't hear you over the sound of mathematics. Convenience is about productivity, and that's largely influence by how much prior knowledge someone needs before being able to understand a features behavior. Floating point calculus basics are easy to understand. (ps. if you're going to use Argumentum ad Verecundiam, I get to use Argumentum ad Populum). So forget coding ! For numerical works, because 0 behaves nicely most of the time, non properly initialized variables may not detected because the output data can sound resoneable; on the other hand, because NaN blows up, such detection is straight forward: the output will be a NaN output which will jump to your face very quickly. I gave examples which address this. This behavior is only [debatably] beneficial in corner cases on FP numbers specifically. I don't think that sufficient justification in light of reasons I give above. This is more than sufficient because the authority for floating point (aka numerical) stuff is hold by numerical folks. This is a numerical issue, not a coding language issue. No, it's both. So a choice has to be done: the mature choice is NaN approach. We're not Theoretical physicists I am we're Software Engineers writing a very broad scope of different programs. Does floating point calculation belong to the broad scope ? Do engineers relay on numerical mathematician skills when they code numerical stuff, or on pre-calculus books for grocers ? Personally in my C code, I have taken the habit to initialise real numbers (doubles) with NaN: in the GSL library there is a ready to use macro: GSL_NAN. (Concerning, integers I used extreme value as INT_MIN, INT_MAX, SIZE_MAX. ...). Only useful because C defaults to garbage. It can be initialized by 0.0 as well. I would even say that D may go further by setting a kind of NaN for integers (and for chars). You may get your with if Arm64 takes over.
Re: A "general" tag
On Saturday, 14 April 2012 at 19:17:52 UTC, Xan wrote: Hi, I try to translate a script I wrote in Fantom [www.fantom.org]. In my script, I have a type "Tag" defined as a triple of: - String (the name of the tag), - Type (the type of the tag: could be Str, Date, Int, etc.) - Obj (the value of the tag; Fantom has Objects of Top-Class hierachy). (normally the tag has Type = Obj.Type, but you can manually set). For example, you could have: (name, Str#, "John") or (date, Date#, 2011-09-02) (# is the Fantom way for specifying type: Str# is the sys::Str type) Is there any way for emulating this? My main trouble is how to define Type and Object in D. Thanks in advance, Xan. PS: Please, be patient, I'm a newbee. For "Type" look at enum (http://dlang.org/enum.html) and for "Object" look at std.variant (http://dlang.org/phobos/std_variant.html). And since Variant can tell you what type it contains you might no longer need that "Type" parameter.
Re: D 50% slower than C++. What I'm doing wrong?
On 14/04/12 21:05, ReneSac wrote: Lang| Comp | Binary size | Time (lower is better) C++ (g++) - 13kb - 2.42s (100%) -O3 -s D (DMD) - 230kb - 4.46s (184%) -O -release -inline D (GDC) - 1322kb - 3.69s (152%) -O3 -frelease -s Try using extra optimizations for GDC. Actually, GDC has a "dmd-like" interface, gdmd, and gdmd -O -release -inline corresponds to gdc -O3 -fweb -frelease -finline-functions ... so there may be some optimizations you were missing. (If you call gdmd with the -vdmd flag, it will tell you exactly what gdc statement it's using.) The only diference I could see between the C++ and D versions is that C++ has hints to the compiler about which functions to inline, and I could't find anything similar in D. So I manually inlined the encode and decode functions: GDC has all the regular gcc optimization flags available IIRC. The ones on the GDC man page are just the ones specific to GDC. Still, the D version is slower. What makes this speed diference? Is there any way to side-step this? In my (brief and limited) experience GDC produced executables tend to have a noticeable but minor gap compared to equivalent g++ compiled C++ code -- nothing on the order of 150%. E.g. I have some simulation code which models a reputation system where users rate objects and are then in turn judged on the consistency of their ratings with the general consensus. A simulation with 1000 users and 1000 objects takes ~22s to run in C++, ~24s in D compiled with gdmd -O -release -inline. Scale that up to 2000 users and 1000 objects and it's 47s (C++) vs 53s (D). 2000 users and 2000 objects gives 1min 49s (C++) and 2min 4s (D). So, it's a gap, but not one to write home about really, especially when you count that D is safer and (I think) easier/faster to program in. It's true that DMD is much slower -- the GCC backend is much better at generating fast code. If I recall right the DMD backend's encoding of floating point operations is considerably less sophisticated. Note that this simple C++ version can be made more than 2 times faster with algoritimical and io optimizations, (ab)using templates, etc. So I'm not asking for generic speed optimizations, but only things that may make the D code "more equal" to the C++ code. I'm sure you can make various improvements to your D code in a similar way, and there are some things that improve in D when written in idiomatic "D style" as opposed to a more C++ish way of doing things (e.g. if you want to copy 1 vector to another, as happens in my code, write x[] = y[] instead of doing any kind of loop). Best wishes, -- Joe
Re: D 50% slower than C++. What I'm doing wrong?
On Saturday, 14 April 2012 at 19:05:40 UTC, ReneSac wrote: I have this simple binary arithmetic coder in C++ by Mahoney and translated to D by Maffi. I added "notrow", "final" and "pure" and "GC.disable" where it was possible, but that didn't made much difference. Adding "const" to the Predictor.p() (as in the C++ version) gave 3% higher performance. Here the two versions: http://mattmahoney.net/dc/ <-- original zip http://pastebin.com/55x9dT9C <-- Original C++ version. http://pastebin.com/TYT7XdwX <-- Modified D translation. The problem is that the D version is 50% slower: test.fpaq0 (16562521 bytes) -> test.bmp (33159254 bytes) Lang| Comp | Binary size | Time (lower is better) C++ (g++) - 13kb - 2.42s (100%) -O3 -s D(DMD) - 230kb - 4.46s (184%) -O -release -inline D(GDC) -1322kb - 3.69s (152%) -O3 -frelease -s The only diference I could see between the C++ and D versions is that C++ has hints to the compiler about which functions to inline, and I could't find anything similar in D. So I manually inlined the encode and decode functions: http://pastebin.com/N4nuyVMh - Manual inline D(DMD) - 228kb - 3.70s (153%) -O -release -inline D(GDC) -1318kb - 3.50s (144%) -O3 -frelease -s Still, the D version is slower. What makes this speed diference? Is there any way to side-step this? Note that this simple C++ version can be made more than 2 times faster with algoritimical and io optimizations, (ab)using templates, etc. So I'm not asking for generic speed optimizations, but only things that may make the D code "more equal" to the C++ code. I wrote a version http://codepad.org/phpLP7cx based on the C++ one. My commands used to compile: g++46 -O3 -s fpaq0.cpp -o fpaq0cpp dmd -O -release -inline -noboundscheck fpaq0.d G++ 4.6, dmd 2.059. I did 5 tests for each: test.fpaq0 (34603008 bytes) -> test.bmp (34610367 bytes) The C++ average result was 9.99 seconds (varying from 9.98 to 10.01) The D average result was 12.00 seconds (varying from 11.98 to 12.01) That means there is 16.8 percent difference in performance that would be cleared out by usage of gdc (which I don't have around currently).
Thread join behaviour
I thought the following would terminate gracefully having printed 0..9 in some (random) order: #! /usr/bin/env rdmd import std.algorithm ; import std.range ; import std.stdio ; import core.thread ; int main ( immutable string[] args ) { auto threads = map ! ( ( int a ) { void delegate ( ) f ( ) { return delegate ( ) { writeln ( a ) ; } ; } return new Thread ( f ) ; } ) ( iota ( 10 ) ) ; foreach ( t ; threads ) { t.start ( ) ; } foreach ( t ; threads ) { t.join ( ) ; } return 0 ; } However, this does not happen, at least with 2.059 on Linux as per Debian Unstable. Instead I get: 1 2 4 5 8 3 7 6 9 0 core.thread.ThreadException@src/core/thread.d(906): Unable to join thread /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(_Dmain+0x83) [0x425edb] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void runMain()+0x17) [0x429bab] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void runAll()+0x3d) [0x429bf9] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2.main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(main+0xd3) [0x4294c3] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd) [0x7f1ed17f8ead] I think I must be having a dumb moment as my reaction continues to be WTF. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: D 50% slower than C++. What I'm doing wrong?
Forgot to mention specs: Dualcore Athlon II X2 240 (2.8GHz), 4GB RAM, FreeBSD 9 x64, both compilers are 64bit.
Re: Calling delegate properties without parens
On 04/14/12 20:47, Piotr Szturmaj wrote: > I have following code: > > import std.array, std.range, std.stdio; > > struct CommonInputRange(E) > { > @property bool delegate() empty; > @property E delegate() front; > void delegate() popFront; > } > > void main(string[] args) > { > alias CommonInputRange!dchar DCRange; > static assert(isInputRange!DCRange); > DCRange dc; > auto dcr = "abcdefg"; > auto t = dcr.takeExactly(3); > dc.empty = &t.empty; > dc.front = &t.front; > dc.popFront = &t.popFront; > > for ( ; !dc.empty(); dc.popFront()) > writeln(dc.front()); > } > > As you can see in the for loop, range primitives must be called using parens > (), otherwise they don't work. > > Do you know if there are plans to implement @property for delegates and > function pointers? @property is for functions masquerading as data, i'm not sure extending it to pointers and delegates would be a good idea. What you are asking for is basically syntax sugar for: struct CommonInputRange(E) { bool delegate() _empty; @property auto empty() { return _empty(); }; @property auto empty(typeof(_empty) dg) { _empty = dg; }; E delegate() _front; @property auto front() { return _front(); }; @property auto front(typeof(_front) dg) { _front = dg; }; void delegate() popFront; } // [1] artur [1] which could also /almost/ be expressed as: struct PropDeleg(T) { T dg; @property auto get() { return dg(); }; alias get this; void opAssign(T d) { dg = d; }; } struct CommonInputRange(E) { PropDeleg!(bool delegate()) empty; PropDeleg!(E delegate()) front; void delegate() popFront; } except this one would need an (implicit) conversion to get the same behavior. IOW it should work everywhere, as long as the result is assigned to a different type; ie you'd need "{ dchar c = dc.front; writeln(c); }" in the above example, because otherwise the writeln template will accept the struct, but never really use it, so the dchar conversion does not happen.
Re: A "general" tag
On Saturday, 14 April 2012 at 19:40:06 UTC, Aleksandar Ružičić wrote: On Saturday, 14 April 2012 at 19:17:52 UTC, Xan wrote: Hi, I try to translate a script I wrote in Fantom [www.fantom.org]. In my script, I have a type "Tag" defined as a triple of: - String (the name of the tag), - Type (the type of the tag: could be Str, Date, Int, etc.) - Obj (the value of the tag; Fantom has Objects of Top-Class hierachy). (normally the tag has Type = Obj.Type, but you can manually set). For example, you could have: (name, Str#, "John") or (date, Date#, 2011-09-02) (# is the Fantom way for specifying type: Str# is the sys::Str type) Is there any way for emulating this? My main trouble is how to define Type and Object in D. Thanks in advance, Xan. PS: Please, be patient, I'm a newbee. For "Type" look at enum (http://dlang.org/enum.html) and for "Object" look at std.variant (http://dlang.org/phobos/std_variant.html). And since Variant can tell you what type it contains you might no longer need that "Type" parameter. I think it's not what I expect. Can I have a generic object type? Something like an assigment like: Any a ? With templates? Please, guide me. I'm a newbee
Re: Thread join behaviour
On 14-04-2012 18:04, Russel Winder wrote: I thought the following would terminate gracefully having printed 0..9 in some (random) order: #! /usr/bin/env rdmd import std.algorithm ; import std.range ; import std.stdio ; import core.thread ; int main ( immutable string[] args ) { auto threads = map ! ( ( int a ) { void delegate ( ) f ( ) { return delegate ( ) { writeln ( a ) ; } ; } return new Thread ( f ) ; } ) ( iota ( 10 ) ) ; foreach ( t ; threads ) { t.start ( ) ; } foreach ( t ; threads ) { t.join ( ) ; } return 0 ; } However, this does not happen, at least with 2.059 on Linux as per Debian Unstable. Instead I get: 1 2 4 5 8 3 7 6 9 0 core.thread.ThreadException@src/core/thread.d(906): Unable to join thread /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(_Dmain+0x83) [0x425edb] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void runMain()+0x17) [0x429bab] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void runAll()+0x3d) [0x429bf9] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(main+0xd3) [0x4294c3] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd) [0x7f1ed17f8ead] I think I must be having a dumb moment as my reaction continues to be WTF. http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_join.3.html#ERRORS We can rule out these: EDEADLK: Can't happen with your code. EINVAL (second case): No other thread is trying to join. ESRCH: Shouldn't happen since druntime registers threads with libpthread. So, the first case of EINVAL (thread is not a joinable thread) must be the cause. I have no clue *why* though... -- - Alex
Re: D 50% slower than C++. What I'm doing wrong?
Le 14/04/2012 21:53, q66 a écrit : > On Saturday, 14 April 2012 at 19:05:40 UTC, ReneSac wrote: >> I have this simple binary arithmetic coder in C++ by Mahoney and >> translated to D by Maffi. I added "notrow", "final" and "pure" and >> "GC.disable" where it was possible, but that didn't made much >> difference. Adding "const" to the Predictor.p() (as in the C++ >> version) gave 3% higher performance. Here the two versions: >> >> http://mattmahoney.net/dc/ <-- original zip >> >> http://pastebin.com/55x9dT9C <-- Original C++ version. >> http://pastebin.com/TYT7XdwX <-- Modified D translation. >> >> The problem is that the D version is 50% slower: >> >> test.fpaq0 (16562521 bytes) -> test.bmp (33159254 bytes) >> >> Lang| Comp | Binary size | Time (lower is better) >> C++ (g++) - 13kb - 2.42s (100%) -O3 -s >> D(DMD) - 230kb - 4.46s (184%) -O -release -inline >> D(GDC) -1322kb - 3.69s (152%) -O3 -frelease -s >> >> >> The only diference I could see between the C++ and D versions is that >> C++ has hints to the compiler about which functions to inline, and I >> could't find anything similar in D. So I manually inlined the encode >> and decode functions: >> >> http://pastebin.com/N4nuyVMh - Manual inline >> >> D(DMD) - 228kb - 3.70s (153%) -O -release -inline >> D(GDC) -1318kb - 3.50s (144%) -O3 -frelease -s >> >> Still, the D version is slower. What makes this speed diference? Is >> there any way to side-step this? >> >> Note that this simple C++ version can be made more than 2 times faster >> with algoritimical and io optimizations, (ab)using templates, etc. So >> I'm not asking for generic speed optimizations, but only things that >> may make the D code "more equal" to the C++ code. > > I wrote a version http://codepad.org/phpLP7cx based on the C++ one. > > My commands used to compile: > > g++46 -O3 -s fpaq0.cpp -o fpaq0cpp > dmd -O -release -inline -noboundscheck fpaq0.d > > G++ 4.6, dmd 2.059. > > I did 5 tests for each: > > test.fpaq0 (34603008 bytes) -> test.bmp (34610367 bytes) > > The C++ average result was 9.99 seconds (varying from 9.98 to 10.01) > The D average result was 12.00 seconds (varying from 11.98 to 12.01) > > That means there is 16.8 percent difference in performance that would be > cleared out by usage of gdc (which I don't have around currently). The code is nearly identical (there is a slight difference in update(), where he accesses the array once more than you), but the main difference I see is the -noboundscheck compilation option on DMD.
Re: D 50% slower than C++. What I'm doing wrong?
On Saturday, 14 April 2012 at 20:58:01 UTC, Somedude wrote: Le 14/04/2012 21:53, q66 a écrit : On Saturday, 14 April 2012 at 19:05:40 UTC, ReneSac wrote: I have this simple binary arithmetic coder in C++ by Mahoney and translated to D by Maffi. I added "notrow", "final" and "pure" and "GC.disable" where it was possible, but that didn't made much difference. Adding "const" to the Predictor.p() (as in the C++ version) gave 3% higher performance. Here the two versions: http://mattmahoney.net/dc/ <-- original zip http://pastebin.com/55x9dT9C <-- Original C++ version. http://pastebin.com/TYT7XdwX <-- Modified D translation. The problem is that the D version is 50% slower: test.fpaq0 (16562521 bytes) -> test.bmp (33159254 bytes) Lang| Comp | Binary size | Time (lower is better) C++ (g++) - 13kb - 2.42s (100%) -O3 -s D(DMD) - 230kb - 4.46s (184%) -O -release -inline D(GDC) -1322kb - 3.69s (152%) -O3 -frelease -s The only diference I could see between the C++ and D versions is that C++ has hints to the compiler about which functions to inline, and I could't find anything similar in D. So I manually inlined the encode and decode functions: http://pastebin.com/N4nuyVMh - Manual inline D(DMD) - 228kb - 3.70s (153%) -O -release -inline D(GDC) -1318kb - 3.50s (144%) -O3 -frelease -s Still, the D version is slower. What makes this speed diference? Is there any way to side-step this? Note that this simple C++ version can be made more than 2 times faster with algoritimical and io optimizations, (ab)using templates, etc. So I'm not asking for generic speed optimizations, but only things that may make the D code "more equal" to the C++ code. I wrote a version http://codepad.org/phpLP7cx based on the C++ one. My commands used to compile: g++46 -O3 -s fpaq0.cpp -o fpaq0cpp dmd -O -release -inline -noboundscheck fpaq0.d G++ 4.6, dmd 2.059. I did 5 tests for each: test.fpaq0 (34603008 bytes) -> test.bmp (34610367 bytes) The C++ average result was 9.99 seconds (varying from 9.98 to 10.01) The D average result was 12.00 seconds (varying from 11.98 to 12.01) That means there is 16.8 percent difference in performance that would be cleared out by usage of gdc (which I don't have around currently). The code is nearly identical (there is a slight difference in update(), where he accesses the array once more than you), but the main difference I see is the -noboundscheck compilation option on DMD. He also uses a class. And -noboundscheck should be automatically induced by -release.
Re: Thread join behaviour
On 04/14/2012 04:56 PM, Alex Rønne Petersen wrote: On 14-04-2012 18:04, Russel Winder wrote: I thought the following would terminate gracefully having printed 0..9 in some (random) order: #! /usr/bin/env rdmd import std.algorithm ; import std.range ; import std.stdio ; import core.thread ; int main ( immutable string[] args ) { auto threads = map ! ( ( int a ) { void delegate ( ) f ( ) { return delegate ( ) { writeln ( a ) ; } ; } return new Thread ( f ) ; } ) ( iota ( 10 ) ) ; foreach ( t ; threads ) { t.start ( ) ; } foreach ( t ; threads ) { t.join ( ) ; } return 0 ; } However, this does not happen, at least with 2.059 on Linux as per Debian Unstable. Instead I get: 1 2 4 5 8 3 7 6 9 0 core.thread.ThreadException@src/core/thread.d(906): Unable to join thread /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(_Dmain+0x83) [0x425edb] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void runMain()+0x17) [0x429bab] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void runAll()+0x3d) [0x429bf9] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern (C) int rt.dmain2..main(int, char**).void tryExec(scope void delegate())+0x23) [0x42952b] /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(main+0xd3) [0x4294c3] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd) [0x7f1ed17f8ead] I think I must be having a dumb moment as my reaction continues to be WTF. http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_join.3.html#ERRORS We can rule out these: EDEADLK: Can't happen with your code. EINVAL (second case): No other thread is trying to join. ESRCH: Shouldn't happen since druntime registers threads with libpthread. So, the first case of EINVAL (thread is not a joinable thread) must be the cause. I have no clue *why* though... If you merge the two foreach loops into one, doing t.start();t.join(); it doesn't have this issue. Also, when I run your code repeatedly the number of successful numbers printed changes a lot. I'm assuming that you're trying to join a thread that already exited... -Matt
Re: Thread join behaviour
On 04/14/12 18:04, Russel Winder wrote: > I thought the following would terminate gracefully having printed 0..9 > in some (random) order: > > #! /usr/bin/env rdmd > > import std.algorithm ; > import std.range ; > import std.stdio ; > import core.thread ; > > int main ( immutable string[] args ) { > auto threads = map ! ( ( int a ) { > void delegate ( ) f ( ) { > return delegate ( ) { writeln ( a ) ; } ; > } > return new Thread ( f ) ; > } ) ( iota ( 10 ) ) ; > foreach ( t ; threads ) { t.start ( ) ; } > foreach ( t ; threads ) { t.join ( ) ; } > return 0 ; > } > > However, this does not happen, at least with 2.059 on Linux as per > Debian Unstable. Instead I get: > > 1 > 2 > 4 > 5 > 8 > 3 > 7 > 6 > 9 > 0 > core.thread.ThreadException@src/core/thread.d(906): Unable to join > thread > > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(_Dmain+0x83) > [0x425edb] > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern > (C) int rt.dmain2.main(int, char**).void runMain()+0x17) [0x429bab] > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern > (C) int rt.dmain2.main(int, char**).void tryExec(scope void > delegate())+0x23) [0x42952b] > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern > (C) int rt.dmain2.main(int, char**).void runAll()+0x3d) [0x429bf9] > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern > (C) int rt.dmain2.main(int, char**).void tryExec(scope void > delegate())+0x23) [0x42952b] > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(main+0xd3) > [0x4294c3] > /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd) > [0x7f1ed17f8ead] > > > I think I must be having a dumb moment as my reaction continues to be > WTF. 'threads' is a (lazy) range; auto threads = array(map ! ( ( int a ) { void delegate ( ) f ( ) { return delegate ( ) { writeln ( a ) ; } ; } return new Thread ( f ) ; } ) ( iota ( 10 ) )) ; artur
Re: Thread join behaviour
Le 14/04/2012 18:04, Russel Winder a écrit : > I thought the following would terminate gracefully having printed 0..9 > in some (random) order: > > #! /usr/bin/env rdmd > > import std.algorithm ; > import std.range ; > import std.stdio ; > import core.thread ; > > int main ( immutable string[] args ) { > auto threads = map ! ( ( int a ) { > void delegate ( ) f ( ) { > return delegate ( ) { writeln ( a ) ; } ; > } > return new Thread ( f ) ; > } ) ( iota ( 10 ) ) ; > foreach ( t ; threads ) { t.start ( ) ; } > foreach ( t ; threads ) { t.join ( ) ; } > return 0 ; > } > > However, this does not happen, at least with 2.059 on Linux as per > Debian Unstable. Instead I get: > > 1 > 2 > 4 > 5 > 8 > 3 > 7 > 6 > 9 > 0 > core.thread.ThreadException@src/core/thread.d(906): Unable to join > thread > > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(_Dmain+0x83) > [0x425edb] > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern > (C) int rt.dmain2.main(int, char**).void runMain()+0x17) [0x429bab] > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern > (C) int rt.dmain2.main(int, char**).void tryExec(scope void > delegate())+0x23) [0x42952b] > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern > (C) int rt.dmain2.main(int, char**).void runAll()+0x3d) [0x429bf9] > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(extern > (C) int rt.dmain2.main(int, char**).void tryExec(scope void > delegate())+0x23) [0x42952b] > > /tmp/.rdmd-1000/home/users/russel/Progs/OddsByLanguage/D/Odds/initializingWithAMap.d.9532BBED12C814F25F173A9AEAB96D0D(main+0xd3) > [0x4294c3] > /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd) > [0x7f1ed17f8ead] > > > I think I must be having a dumb moment as my reaction continues to be > WTF. > This works: int main ( immutable string[] args ) { auto threadgroup = new ThreadGroup(); void delegate ( ) f (int a ) { return delegate ( ) { writeln ( a ) ; } ; } for ( int n = 0; n < 10; n++ ) { threadgroup.create(f(n)); } threadgroup.joinAll( ); return 0 ; } Threads are tracked by the threadgroup, which knows who can be joined.
Re: Calling delegate properties without parens
Artur Skawina wrote: @property is for functions masquerading as data, i'm not sure extending it to pointers and delegates would be a good idea. What you are asking for is basically syntax sugar for: struct CommonInputRange(E) { bool delegate() _empty; @property auto empty() { return _empty(); }; @property auto empty(typeof(_empty) dg) { _empty = dg; }; E delegate() _front; @property auto front() { return _front(); }; @property auto front(typeof(_front) dg) { _front = dg; }; void delegate() popFront; } > Yes, I was thinking about this, but it adds unnecessary overhead. I want to call delegates directly. I think the whole idea is harmless because semantically, from the user perspective, delegates and function pointers works just like normal functions. So, why not?
Re: Calling delegate properties without parens
On Saturday, April 14, 2012 20:47:20 Piotr Szturmaj wrote: > I have following code: > > import std.array, std.range, std.stdio; > > struct CommonInputRange(E) > { > @property bool delegate() empty; > @property E delegate() front; > void delegate() popFront; > } > > void main(string[] args) > { > alias CommonInputRange!dchar DCRange; > static assert(isInputRange!DCRange); > DCRange dc; > auto dcr = "abcdefg"; > auto t = dcr.takeExactly(3); > dc.empty = &t.empty; > dc.front = &t.front; > dc.popFront = &t.popFront; > > for ( ; !dc.empty(); dc.popFront()) > writeln(dc.front()); > } > > As you can see in the for loop, range primitives must be called using > parens (), otherwise they don't work. > > Do you know if there are plans to implement @property for delegates and > function pointers? front returns an element in the range. In your case, it's returning a delegate, because you have a range of delegates. If front returned a class or struct with a member function called foo, which you wanted to call, then you'd be doing something like for(; !dc.empty; dc.popFront()) writeln(dc.front.foo()); But in your case, it's a delegate, so operating on that delegate means calling it, which means using the parens. dc.front just gives you the delegate, and it would be horrible if it did anything else. If front also called the delegate, the doing something like auto arr = arr(dc); would call each and every one of the delegates in the range, because it uses front to access the element _without calling it_. If there were some way to indicate that a delegate was called with property syntax, then you could no longer distinguish between simply returning the delegate and returning and call it. Not to mention, properties are supposed to be an abstraction that mimicks member variables. That makes no sense whatsoever with a delegate. And in this case, the member variable which _is_ being mimicked (front) happens to be a delegate. So, it makes perfect sense that you'd have to use parens on it to actually call it. - Jonathan M Davis
Re: D 50% slower than C++. What I'm doing wrong?
I tested the q66 version in my computer (sandy bridge @ 4.3GHz). Repeating the old timmings here, and the new results are marked as "D-v2": test.fpaq0 (16562521 bytes) -> test.bmp (33159254 bytes) Lang| Comp | Binary size | Time (lower is better) C++ (g++) - 13kb - 2.42s (100%) -O3 -s D(DMD) - 230kb - 4.46s (184%) -O -release -inline D(GDC) -1322kb - 3.69s (152%) -O3 -frelease -s D-v2 (DMD) - 206kb - 4.50s (186%) -O -release -inline D-v2 (GDC) - 852kb - 3.65s (151%) -O3 -frelease -s So, basically the same thing... Not using clases seems a little slower on DMD, and no difference on GDC. The "if (++ct[cxt][y] > 65534)" made a very small, but measurable difference (those .04s in GDC). The "if ((cxt += cxt + y) >= 512)" only made the code more complicated, with no speed benefit. But the input file is also important. The file you tested seems to be an already compressed one, or something not very compressible. Here a test with an incompressible file: pnad9huff.fpaq0 (43443040 bytes) -> test-d.huff (43617049 bytes) C++ (g++) - 13kb - 5.13 (100%) -O3 -s D-v2 (DMD) - 206kb - 8.03 (156%) -O -release -inline D-v2 (GDC) - 852kb - 7.09 (138%) -O3 -frelease -s D-inl(DMD) - 228kb - 6.93 (135%) -O -release -inline D-inl(GDC) -1318kb - 6.86 (134%) -O3 -frelease -s The C++ advantage becomes smaller in this file. D-inl is my manual inline version, with your small optimization on "Predictor.Update()". On Saturday, 14 April 2012 at 19:51:21 UTC, Joseph Rushton Wakeling wrote: GDC has all the regular gcc optimization flags available IIRC. The ones on the GDC man page are just the ones specific to GDC. I'm not talking about compiler flags, but the "inline" keyword in the C++ source code. I saw some discussion about "@inline" but it seems not implemented (yet?). Well, that is not a priority for D anyway. About compiler optimizations, -finline-functions and -fweb are part of -O3. I tried to compile with -no-bounds-check, but made no diference for DMD and GDC. It probably is part of -release as q66 said.
Re: D 50% slower than C++. What I'm doing wrong?
On Sunday, April 15, 2012 03:51:59 ReneSac wrote: > About compiler optimizations, -finline-functions and -fweb are > part of -O3. I tried to compile with -no-bounds-check, but made > no diference for DMD and GDC. It probably is part of -release as > q66 said. Not quite. -noboundscheck turns off _all_ array bounds checking, whereas - release turns it off in @system and @trusted functions, but not in @safe functions. But unless you've marked your code with @safe or it uses templated functions which get inferred as @safe, all of your functions are going to be @system functions anyway, in which case, it makes no difference. - Jonathan M Davis
Re: D 50% slower than C++. What I'm doing wrong?
On 14/04/12 23:03, q66 wrote: He also uses a class. And -noboundscheck should be automatically induced by -release. Ahh, THAT probably explains why some of my numerical code is so markedly different in speed when compiled using DMD with or without the -release switch. It's a MAJOR difference -- between code taking say 5min to run, compared to half an hour or more.
Re: D 50% slower than C++. What I'm doing wrong?
On 14/04/12 23:03, q66 wrote: He also uses a class. And -noboundscheck should be automatically induced by -release. ... but the methods are marked as final -- shouldn't that substantially reduce any speed hit from using class instead of struct?
Re: D 50% slower than C++. What I'm doing wrong?
On Sunday, April 15, 2012 04:21:09 Joseph Rushton Wakeling wrote: > On 14/04/12 23:03, q66 wrote: > > He also uses a class. And -noboundscheck should be automatically induced > > by > > -release. > > ... but the methods are marked as final -- shouldn't that substantially > reduce any speed hit from using class instead of struct? In theory. If they don't override anything, then that signals to the compiler that they don't need to be virtual, in which case, they _shouldn't_ be virtual, but that's up to the compiler to optimize, and I don't know how good it is about that right now. Certainly, if you had code like class C { final int foo() { return 42;} } and benchmarking showed that it was the same speed as class C { int foo() { return 42;} } when compiled with -O and -inline, then I'd submit a bug report (maybe an enhancement request?) on the compiler failing to make final functions non- virtual. Also, if the function is doing enough work, then whether it's virtual or not really doesn't make any difference, because the function itself costs so much more than the extra cost of the virtual function call. - Jonathan M Davis
Re: D 50% slower than C++. What I'm doing wrong?
On Saturday, April 14, 2012 19:31:40 Jonathan M Davis wrote: > On Sunday, April 15, 2012 04:21:09 Joseph Rushton Wakeling wrote: > > On 14/04/12 23:03, q66 wrote: > > > He also uses a class. And -noboundscheck should be automatically induced > > > by > > > -release. > > > > ... but the methods are marked as final -- shouldn't that substantially > > reduce any speed hit from using class instead of struct? > > In theory. If they don't override anything, then that signals to the > compiler that they don't need to be virtual, in which case, they > _shouldn't_ be virtual, but that's up to the compiler to optimize, and I > don't know how good it is about that right now. Certainly, if you had code > like > > class C > { > final int foo() { return 42;} > } > > and benchmarking showed that it was the same speed as > > class C > { > int foo() { return 42;} > } > > when compiled with -O and -inline, then I'd submit a bug report (maybe an > enhancement request?) on the compiler failing to make final functions non- > virtual. Actually, if you try and benchmark it, make sure that the code can't know that the reference is exactly a C. In theory, the compiler could be smart enough to know in a case such as auto c = new C; auto a = c.foo(); that c is exactly a C and that therefore, it can just inline the call to foo even if it's virtual. If c is set from another function, it can't do that. e.g. auto c = bar(); auto a = c.foo(); The compiler _probably_ isn't that smart, but it might be, so you'd have to be careful about that. - Jonathan M Davis
Re: D 50% slower than C++. What I'm doing wrong?
On Sunday, 15 April 2012 at 02:20:34 UTC, Joseph Rushton Wakeling wrote: On 14/04/12 23:03, q66 wrote: He also uses a class. And -noboundscheck should be automatically induced by -release. Ahh, THAT probably explains why some of my numerical code is so markedly different in speed when compiled using DMD with or without the -release switch. It's a MAJOR difference -- between code taking say 5min to run, compared to half an hour or more. I know this isn't what your post was about, but you really should compile numerical code with GDC instead of DMD if you care about performance. It generates much faster floating point code.
Re: D 50% slower than C++. What I'm doing wrong?
On 15/04/12 04:37, jerro wrote: I know this isn't what your post was about, but you really should compile numerical code with GDC instead of DMD if you care about performance. It generates much faster floating point code. It's exactly what I do. :-)
Re: D 50% slower than C++. What I'm doing wrong?
On Saturday, 14 April 2012 at 19:51:21 UTC, Joseph Rushton Wakeling wrote: GDC has all the regular gcc optimization flags available IIRC. The ones on the GDC man page are just the ones specific to GDC. I'm not talking about compiler flags, but the "inline" keyword in the C++ source code. I saw some discussion about "@inline" but it seems not implemented (yet?). Well, that is not a priority for D anyway. About compiler optimizations, -finline-functions and -fweb are part of -O3. I tried to compile with -no-bounds-check, but made no diference for DMD and GDC. It probably is part of -release as q66 said. Ah yes, you're right. I do wonder if your seeming speed differences are magnified because the whole operation is only 2-4 seconds long: if your algorithm were operating over a longer timeframe I think you'd likely find the relative speed differences decrease. (I have a memory of a program that took ~0.004s with a C/C++ version and 1s with D, and the difference seemed to be just startup time for the D program.) What really amazes me is the difference between g++, DMD and GDC in size of the executable binary. 100 orders of magnitude! 3 remarks about the D code. One is that much of it still seems very "C-ish"; I'd be interested to see how speed and executable size differ if things like the file opening, or the reading of characters, are done with more idiomatic D code. Sounds stupid as the C stuff should be fastest, but I've been surprised sometimes at how using idiomatic D formulations can improve things. Second remark is more of a query -- can Predictor.p() and .update really be marked as pure? Their result for a given input actually varies depending on the current values of cxt and ct, which are modified outside of function scope. Third remark -- again a query -- why the GC.disable ... ?
Re: D 50% slower than C++. What I'm doing wrong?
(I have a memory of a program that took ~0.004s with a C/C++ version and 1s with D, and the difference seemed to be just startup time for the D program.) I have never seen anything like that. Usually the minimal time to run a D program is something like: j@debian:~$ time ./hello Hello world! real0m0.001s user0m0.000s sys 0m0.000s What really amazes me is the difference between g++, DMD and GDC in size of the executable binary. 100 orders of magnitude! With GDC those flags(for gdmd): -fdata-sections -ffunction-sections -L--gc-sections -L-l help a lot if you want to reduce a size of executable. Besides, this overhead is the standard library and runtime and won't be much larger in larger programs.
Re: D 50% slower than C++. What I'm doing wrong?
On Sunday, 15 April 2012 at 03:41:55 UTC, jerro wrote: (I have a memory of a program that took ~0.004s with a C/C++ version and 1s with D, and the difference seemed to be just startup time for the D program.) I have never seen anything like that. Usually the minimal time to run a D program is something like: j@debian:~$ time ./hello Hello world! real0m0.001s user0m0.000s sys 0m0.000s What really amazes me is the difference between g++, DMD and GDC in size of the executable binary. 100 orders of magnitude! With GDC those flags(for gdmd): -fdata-sections -ffunction-sections -L--gc-sections -L-l help a lot if you want to reduce a size of executable. Besides, this overhead is the standard library and runtime and won't be much larger in larger programs. The last flag should be -L-s
Re: D 50% slower than C++. What I'm doing wrong?
On 15/04/12 05:41, jerro wrote: I have never seen anything like that. Usually the minimal time to run a D program is something like: j@debian:~$ time ./hello Hello world! real 0m0.001s user 0m0.000s sys 0m0.000s Yea, my experience too in general. I can't remember exactly what I was testing but if it's what I think it was (and have just retested:-), the difference may have been less pronounced (maybe 0.080s for D compared to 0.004 for C++) and that would have been due to not enabling optimizations for D. I have another pair of stupid D-vs.-C++ speed-test files where with optimizations engaged, D beats C++: the dominant factor is lots of output to console, so I guess this is D's writeln() beating C++'s cout. What really amazes me is the difference between g++, DMD and GDC in size of the executable binary. 100 orders of magnitude! With GDC those flags(for gdmd): -fdata-sections -ffunction-sections -L--gc-sections -L-l help a lot if you want to reduce a size of executable. Besides, this overhead is the standard library and runtime and won't be much larger in larger programs. Ahh! I hadn't realized that the libphobos package on Ubuntu didn't install a compiled version of the library. (DMD does.)