Monday, May 7, 2018

Digest for comp.lang.c++@googlegroups.com - 25 updates in 5 topics

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: