- Comparison to std::numeric_limits<double>::max() - 9 Updates
- Is reference counting slower than GC? - 2 Updates
- Long identifiers, poor readability - 11 Updates
- I correct a typo, please read again - 2 Updates
- I have thought more about the following paper about Lock Cohorting - 1 Update
Paavo Helde <myfirstname@osa.pri.ee>: Apr 29 11:12PM +0300 On 27.04.2018 13:22, Andrea Venturoli wrote: >> Nevertheless, comparing with std::numeric_limits<double>::max() seems >> pretty fragile > Why then? Comparing floating-point numbers for exact equality is always fragile, there is always a chance that somebody adds some computation like divide by 10, multiply by 10, ruining the results. A deeply "floating-point" value like std::numeric_limits<double>::max() is doubly suspect just because it is far away from normal and well-tested range of values. I just checked how it is defined in MSVC. It appears the value is defined by the macro #define DBL_MAX 1.7976931348623158e+308 From here you can clearly see there might be problems. This constant is specified in decimal and I believe there is a fair chance this number does not have an exact representation in binary. It will probably yield different results when loaded into either a 64-bit or a 80-bit register. Add some minor optimizer bugs and one can easily imagine that there might be problems when comparing this number with itself, even if it should work by the letter of the standard. |
Tim Rentsch <txr@alumni.caltech.edu>: Apr 29 10:16PM -0700 > The failure you see of std::numeric_limits<double>::max() > to compare equal to itself [...] (probably) does not violate > the letter of the c++ standard. What leads you to think the C++ standard allows this? Are there any specific citations you can offer that support this view? AFAICT the C and C++ standards admit no leeway, and the comparison must give a result of equal. |
Tim Rentsch <txr@alumni.caltech.edu>: Apr 29 10:41PM -0700 > number does not have an exact representation in binary. It will > probably yield different results when loaded into either a 64-bit or a > 80-bit register. None of those things matter. The Standard requires a particular value be returned, however the implementation chooses to do it. > Add some minor optimizer bugs and one can easily > imagine that there might be problems when comparing this number with > itself, even if it should work by the letter of the standard. If you don't trust your compiler, get a different compiler. If you think it's important to run sanity checks be sure the compiler doesn't have bugs, by all means do so. But don't give in to superstitious programming practices. Insist on solid understanding and a rational decision process, not murky justifications based on uncertainty and fear. Anyone promoting voodoo programming principles should be encouraged to change occupations from developer to witchdoctor. |
Juha Nieminen <nospam@thanks.invalid>: Apr 30 05:57AM >> 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.00000000000000000000 >> 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.00000000000000000000 > The two numbers are the same to the last digit. If you want to print two floating point numbers in order to see if they are bit-by-bit identical, you shouldn't print the in decimal. Conversion to decimal may cause rounding errors (because floating point values are internally represented in terms of powers of 2, while decimal is in terms of powers of 10). Either print the raw byte values of the floating point variable (eg. in binary format), or use std::printf with the format specifier "%a" which prints it in hexadecimal. (This is a bit-by-bit accurate representation because converting from base-2 to base-16 can be done losslessly, without need for rounding.) There might have been an equivalent to "%a" for std::ostream, but I don't remember now if there was. |
Paavo Helde <myfirstname@osa.pri.ee>: Apr 30 11:10AM +0300 On 30.04.2018 8:41, Tim Rentsch wrote: >> imagine that there might be problems when comparing this number with >> itself, even if it should work by the letter of the standard. > If you don't trust your compiler, get a different compiler. That's not about my compiler. I need the code to be compiled by different compilers and we do not have time or resources to test them all, especially those which have not yet been written. > If you think it's important to run sanity checks be sure the > compiler doesn't have bugs, by all means do so. Thanks, our software has a huge suite of automatic unit and integration tests. With their help we recently located and eliminated a randomly flipping bit in the physical memory of the testing server which the memory diagnostic tools failed to diagnose. > justifications based on uncertainty and fear. Anyone promoting > voodoo programming principles should be encouraged to change > occupations from developer to witchdoctor. What one man calls superstitious hunch, another man calls experience. I would not have written a direct comparison with std::numeric_limits<double>::max() because I have had some experience with compiler/optimizer bugs and where are the murky corners. As it came out else-thread my suspicions were justified, the problem indeed appears to be a bug in the compiler, triggered indeed by the presence of std::numeric_limits<double>::max() in the code (albeit the bug was a different and more interesting one from what I had imagined). I get payed for writing software working as reliably as possible in the real world. This has a lot to do with anticipating and avoiding or working around any bugs or problems in the standards/OS-es/compilers/toolchains/third-party libraries, etc. |
Andrea Venturoli <ml.diespammer@netfence.it>: Apr 30 10:05AM +0200 On 04/27/18 08:44, Andrea Venturoli wrote: > Hello. > ... First off, thanks to anyone who got intersted in the matter. I wrote to the clang-dev mailing list and received a precise answer. I'll try to summarize everything here: _ my first assumption that comparing std::numeric_limts<double>::max() to itself was failing was wrong; the problem was another; _ BTW, this comparing must work (or it would be a bug in the compiler/system/etc...); _ my real problem was that: a) I had enabled FP exceptions (in particular overflow); b) with optimizations on, the compiler would speculatively execute a branch that would not run under proper program flow and such a branch generated an FP exception. _ My code was deemed as problematic because, in order to enable exceptions (or use anything from <cenv>), the compiler should be informed (by using #pragma STDC FENV_ACCESS on). Failure to do this will let the optimizer take wrong assumptions. _ BTW, I found some sources which say the above actually is C++ standard, some say it's C standard (possibly inherited by C++ or not), some say it's an extension a compiler might support. I don't have access to C++ standard. _ In any case, Clang does not support that #pragma, so there's right now no way to get FP exception to play nicely with optimizations. There's work going on, but no estimate on the release. bye av. |
boltar@cylonHQ.com: May 07 08:31AM On Fri, 4 May 2018 20:30:37 +0200 >The reason for using floating point is to deal with a large dynamic >range, without having to sacrifice relative accuracy at one end of the >range. Look at those goalposts shift! >const double m = 9.10938356e-31; >const double c = 2.99792458e8; >return h / std::sqrt(e * voltage * m * (e * voltage / (m * c*c) + 2.0)); And the result of that would be accurate would it? I hope its not code for any safety related control system. >I leave it as an exercise for you to figure out how many bits would >required to do the same thing with fixed point numbers without loosing >accuracy compared to the floating point implementation. I wasn't proposing either/or, a language could have both types. |
boltar@cylonHQ.com: May 07 08:32AM On Sat, 5 May 2018 07:40:28 +0200 >> a language instead of having to do calculations using integers. >You keep repeating this, but I don't understand why you need fixed point >"native" to the langugage? In C++, surely you wouldn't do the Why not have it? >application logic using explicit integers, but write your own >fixed-point class and use that. I.e., instead of I was talking about C too. Good luck writing a number class in that. |
Robert Wessel <robertwessel2@yahoo.com>: May 07 12:38PM -0500 >>return h / std::sqrt(e * voltage * m * (e * voltage / (m * c*c) + 2.0)); >And the result of that would be accurate would it? I hope its not code for any >safety related control system. Why wouldn't it be? Assuming a suitable range of values for voltage (within a few orders of magnitude of 10**-4), the various constants being correct, and the formula being correct. Performing multiplicative* operations on FP numbers of wildly differing magnitudes does not lose accuracy. Additive operations *do*, which is where the range limit mentioned for voltage comes from. *Multiplication, division and square root in this case |
Juha Nieminen <nospam@thanks.invalid>: May 07 06:04AM > Is reference counting slower than GC? GC implementations tend to make allocation and deallocation significantly more efficient (in the immediate sense at least). If you allocate and deallocate a million individual small objects in C++ at random, it will be really slow (which is why you generally want to avoid doing that like the plague), while in languages like Java and C# it's a complete non-issue. Also, handling reference-counted pointers adds a layer of overhead which doesn't need to exist in a GC'd environment (each time you copy or assign a reference-counted pointer, there's an additional step involved, which isn't so in GC'd environment. This is also why you generally want to avoid reference-counted smart pointers in C++ if it's reasonable to do so, at least in situations where such pointers are copied and assigned around a lot.) Also, many/most GC language implementations allow for optimization techniques that are simply not possible in C/C++, such as memory compaction (which helps with memory fragmentation and cache locality). A lot of work has been done over the decades to make the garbage collection sweeping process as light-weight as possible, and have as little impact as possible on the performance of the program. I haven't followed how well they have succeeded in this, however. That being said, there are of course compromises with GC. Programs written in GC'd languages tend to consume more memory than eg. C++ programs that have even a modicum of memory usage optimality (because in C++ you can handle objects by value instead of being forced to allocate every single object dynamically). C++ often allows for low-level ("hacker") optimizations to make programs more efficient in terms of speed and memory usage, which many "higher-level" GC'd languages simply don't support. OTOH, many advocates of GC'd (so-called "safe") languages are completely ready to pay that small price for the commodity of not having to think about memory management and let the language and runtime environment take care of it, even if it means slightly increased memory usage and perhaps a bit slower of a program. |
"Öö Tiib" <ootiib@hot.ee>: May 06 11:27PM -0700 On Monday, 7 May 2018 09:04:15 UTC+3, Juha Nieminen wrote: > allows for low-level ("hacker") optimizations to make programs > more efficient in terms of speed and memory usage, which many > "higher-level" GC'd languages simply don't support. Choice of handling some objects by value and others by reference does not have to be so low-level like in C++. For example in Swift (the idea came perhaps from D) if to declare a type "struct" then instances are handled by value and "class" type instances are handled by reference. |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 29 06:23AM On Sat, 2018-04-28, Jouko Koski wrote: > Having to repeat the namespace name everywhere does not improve readability. > It adds noise, induces boilerplate typing and it looks ugly, albeit it does > make the identifiers more explicit. Then I'm with Juha (I think it was): I think accepting the namespaces is the best overall solution. So I refer to things as "std::foo" and to "bar::foo" in my code (if that code isn't also in bar). It no longer looks ugly to me, and it typically doesn't mean a lot of repetition (especially nowadays with C++11 auto). I've done some work with boost::asio, and there the long namespacing /was/ annoying, because you had to mention it over and over again. > }; > so that string would be std::string in this interface without leaking the > same using or alias declaration to everywhere else, too. Any suggestions? If we focus on the interface: to me, if that had appeared in a header file, I'd worry about what 'string' meant, since it didn't say 'std::string'. It doesn't feel like an improvement to struct thing { void func(std::string s); }; I can appreciate an abbreviation like this in an interface: using ResolverMap = std::map<std::string, std::list<IpAddress>>; but then I'm getting something more than removal of the std prefix. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
"Jouko Koski" <joukokoskispam101@netti.fi>: Apr 29 08:37PM +0300 "Alf P. Steinbach" wrote: > using string = std::string; > void func( string const& ); > }; Yes, and a typedef would do as well. Now, can this be scaled so that other identifiers from or even the whole std:: would be available inside the struct? -- Jouko |
"Jouko Koski" <joukokoskispam101@netti.fi>: Apr 29 08:45PM +0300 "James Kuyper" wrote: >> same using or alias declaration to everywhere else, too. Any suggestions? > Can you suggest an alternative, and define the details of how you think > this alternative should work? I thought I was asking the question. :-) Well, the ultimate goal is to improve readability in a bit broader context than in an interface consisting of one class with one member function. But these would be my shots with this minimalistic example so far: using namespace std; // considered bad struct thing { void func(string s); }; This is the non-solution, because it leaks std to anybody using the thing. struct thing { typedef std::string string; // or using string = std::string; void func(string s); }; This is a solution. However, it does not scale, because a typedef is necessary for each "beautified" type in the class scope. The solution carries a lot of boilerplate: We have written "string" three times! struct thing { using namespace std; // not valid C++ void func(string s); }; If this were allowed it would probably the best solution. But there might be some implications... namespace some_unique_boilerplate_namespace_name { using namespace std; struct thing { void func(string s); }; } using some_unique_boilerplate_namespace_name::thing; This is the best I have come up with. But shall we really conclude that the general guideline is: Place all your code in a namespace even when you are not supposed to use a namespace; and place all your code in a nested namespace when you are using a namespace? -- Jouko |
"Jouko Koski" <joukokoskispam101@netti.fi>: Apr 29 09:23PM +0300 wrote: > I would write it like this: > using ResolverMap = ::std::map<::std::string,::std::list<IpAddress>>; Now, this is plain unbeliavable madness! This may solve some problem, but that problem has very little to do with programming. A code review with professional programmers or other professional help might give guidance realizing that this kind of a convention results in just a pile of personal read-only code. -- Jouko |
"Jouko Koski" <joukokoskispam101@netti.fi>: Apr 29 09:13PM +0300 "Jorgen Grahn" wrote: > Then I'm with Juha (I think it was): I think accepting the namespaces > is the best overall solution. So I refer to things as "std::foo" and > to "bar::foo" in my code (if that code isn't also in bar). Making a virtue of necessity! Yes, it is more explicit, but it cripples readability. > It no longer looks ugly to me, and it typically doesn't mean a lot of > repetition (especially nowadays with C++11 auto). Well, it is ugly and there is still a lot of repetition. > If we focus on the interface: to me, if that had appeared in a header > file, I'd worry about what 'string' meant, since it didn't say > 'std::string'. I trust you not being that inept in real life! People using some other languages that have packages or modules mechanism seem to do quite ok with this issue. If there were "string", "buffer" or "socket" in some declaration and there is "std" or "boost::asio" in the same cognitive scope, one should be able to assume that string, buffer or socket cannot be just anything. They are supposed to be coming from std or boost::asio without the need of repeating the full namespace path on every single occurrence. When it comes to this particular toy example, string is probably the most used type in the standard library. I would expect that if there were any other kind of string in the same context simultaneously, it is that string that should be addressed as the other::string without having to drag the std:: prefix to everywhere else. Having "using namespace std;" in the global scope might not be that bad idea after all but that is another story. > I can appreciate an abbreviation like this in an interface: > using ResolverMap = std::map<std::string, std::list<IpAddress>>; > but then I'm getting something more than removal of the std prefix. Yes. When it comes to code readability, this declaration is over 60 characters long. It is a bit challenging to try to limit the max line length to 80 when this kind of stuff tends to be the norm. About 10 % of it is colons and the "std::" is repeated three times. That resembles noise. -- Jouko |
Ian Collins <ian-news@hotmail.com>: Apr 30 07:17AM +1200 On 04/30/2018 06:23 AM, Jouko Koski wrote: > with professional programmers or other professional help might give > guidance realizing that this kind of a convention results in just a > pile of personal read-only code. All of the superfluous colons do make it had to read, take them away and it isn't as bad.... -- Ian. |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Apr 29 07:58PM On Sun, 2018-04-29, Jouko Koski wrote: >> It no longer looks ugly to me, and it typically doesn't mean a lot of >> repetition (especially nowadays with C++11 auto). > Well, it is ugly and there is still a lot of repetition. I note that I wrote "looks ugly to me", and that you still pretend your preferences are universal. >> file, I'd worry about what 'string' meant, since it didn't say >> 'std::string'. > I trust you not being that inept in real life! Ad hominem this soon? I have better things to do. *plonk* /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
Vir Campestris <vir.campestris@invalid.invalid>: Apr 29 09:53PM +0100 On 29/04/2018 19:13, Jouko Koski wrote: > length to 80 when this kind of stuff tends to be the norm. About 10 % > of it is colons and the "std::" is repeated three times. That resembles > noise. Two things: Why would I want to limit the line to 80 chars? My screen is bigger than that, and has been for 20 years at least. And using ResolverMap = std::map< std::string, std::list< IpAddress >; Andy. -- Apparently the Linux kernel standard is to stop excessive nesting. so why doesn't it limit nesting instead? |
Juha Nieminen <nospam@thanks.invalid>: Apr 30 05:43AM > When examined in isolation, yes. However, this pattern does often > repeat and it becomes a tedious pain in the neck. Code readability requires following coding conventions. Writing namespace prefixes can be a good coding convention. |
Paavo Helde <myfirstname@osa.pri.ee>: Apr 30 09:03AM +0300 On 29.04.2018 20:45, Jouko Koski wrote: >> this alternative should work? > I thought I was asking the question. :-) Well, the ultimate goal is to > improve readability One thing you forget here is that readability depends on the reader. What is easily recognized by one reader might not be recognized by another. If I am familiar with the codebase and know there is no custom string class there, then seeing a type name string automatically means this must be a std::string. If I am not familiar with the codebase, then it is not so clear at all. When I see an identifier like socket in some foreign or long-forgotten code I am just trying to debug this is not readable at all. What does it mean, how do I construct one? Man socket says it is a function. I will need to figure out somehow that it is a boost::asio::ip::tcp::socket (or then something else). If I read this code once in 5 years, I would like to have it all spelled out. If I read and write this code each day, then I want it to be shortened to just socket. The readability goals are different. |
"Jouko Koski" <joukokoskispam101@netti.fi>: Apr 30 12:02PM +0300 "Vir Campestris" wrote: > Two things: > Why would I want to limit the line to 80 chars? My screen is bigger than > that, and has been for 20 years at least. 80 may not be the exact value, but longer lines tend to deteriorate readability, and that is fairly universal. Then, team members may be reading code on paper or on their smartphones, and there are still old vga projectors out there. Some people may be visually impaired or just prefer to use the ample horizontal space for placing the working windows side by side. > std::list< > IpAddress > >; Line folding tend to break the visual flow. Folding convention and indentation do matter. Sometimes it may be insightful to replace all printable characters in a source file (or in any text, for the matter!) with X characters, and assess if the pattern still communicates structure, function, and intent. > Apparently the Linux kernel standard is to stop excessive nesting. so > why doesn't it limit nesting instead? Well, it does, doesn't it? -- Jouko |
Sky89 <Sky89@sky68.com>: Apr 28 11:11PM -0400 Hello, I correct a typo, please read again: I have thought more about the following paper about Lock Cohorting: A General Technique for Designing NUMA Locks: http://groups.csail.mit.edu/mag/a13-dice.pdf I think it is not a "bright" idea, this NUMA Locks that uses Lock Cohorting do not optimize the inside of the critical sections protected by the NUMA Locks that use Lock Cohorting, because the inside of those critical sections may transfer/bring Data from different NUMA nodes, so this will cancel the gains that we have got from NUMA Locks that uses Lock cohorting. So i don't think i will implement Lock Cohorting. So then i have invented my scalable AMLock and scalable MLock, please read for example about my scalable MLock here: https://sites.google.com/site/aminer68/scalable-mlock You can download my scalable MLock for C++ by downloading my C++ synchronization objects library that contains some of my "inventions" here: https://sites.google.com/site/aminer68/c-synchronization-objects-library The Delphi and FreePascal version of my scalable MLock is here: https://sites.google.com/site/aminer68/scalable-mlock Thank you, Amine Moulay Ramdane. |
Juha Nieminen <nospam@thanks.invalid>: Apr 30 05:58AM > I correct a typo, please read again: Could you please stop spamming? If the topic is C++, then it's fine, but just stop spamming the same thing over and over. |
Sky89 <Sky89@sky68.com>: Apr 28 11:08PM -0400 Hello.. I have thought more about the following paper about Lock Cohorting: A General Technique for Designing NUMA Locks: http://groups.csail.mit.edu/mag/a13-dice.pdf I think it is not a "bright" idea, this NUMA Locks that uses Lock Cohorting do not optimize the inside of the critical section protected by the NUMA Locks that use Lock Cohorting, because the inside of those critical sections may transfer/bring Data from different NUMA nodes, so this will cancel the gains that we have got from NUMA Locks that uses Lock cohorting. So i don't think i will implement Lock Cohorting. So then i have invented my scalable AMLock and scalable MLock, please read for example about my scalable MLock here: https://sites.google.com/site/aminer68/scalable-mlock You can download my scalable MLock for C++ by downloading my C++ synchronization objects library that contains some of my "inventions" here: https://sites.google.com/site/aminer68/c-synchronization-objects-library The Delphi and FreePascal version of my scalable MLock is here: https://sites.google.com/site/aminer68/scalable-mlock Thank you, Amine Moulay Ramdane. |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment