lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] rate_table_tool: merge a whole directory


From: Greg Chicares
Subject: Re: [lmi] rate_table_tool: merge a whole directory
Date: Sun, 4 Dec 2016 23:03:14 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Icedove/45.4.0

On 2016-12-04 17:28, Vadim Zeitlin wrote:
> On Sat, 3 Dec 2016 22:22:20 +0000 Greg Chicares <address@hidden> wrote:
> 
> GC> Furthermore, converting the value manually as in HEAD at this moment
> GC> is less accurate than using std::strtod().
[...]
>  So, I wrote a small test program that just dumbly iterates over all
> possible strings of the form "0.ddddd" with the given number of digits
> after the point and compares the results of using strtoul() and dividing
> by the exponent manually and calling strtod, here it is:
[...]
>  Running this program for the number of decimals up to 10 (but you'd better
> use threads if you use this precision, it takes roughly 10 minutes with
> them and so would take an hour and a half without) doesn't detect any
> discrepancies when it's compiled with either MSVS 2015 or g++ 4.9.1 under
> Linux x64. However compiling it with MinGW 4.9.1 compiler lmi uses or (and
> this is the part which took me an embarrassingly long time to understand)
> in 32 bit mode under Linux, shows plenty of discrepancies starting from
> NUM_DECIMALS=6 (there are none for 5).

I'm surprised. Separating a string like 'n.nnnnn' (with no more than about
ten digits in practice) into integral and fractional parts leaves no room
for any numerical discrepancy, but this algorithm does:

    double value = res_frac_part.num;
    value /= std::pow(10, *num_decimals_);
    value += res_int_part.num;

Given that num_decimals_ is a small integer, I'd hope that std::pow() would
return an exact integer value...but IIRC that wasn't reliably true for older
versions of MinGW; and I'm not sure the standard requires that to be true,
though it's certainly a QoI issue if it's not true.

However, more seriously, if we do what the code literally says, then given
"1.23456", we form the integer 23456, divide it by 100000, round it to
double precision, and store it. Then we add an integer to it and round the
result, which causes the loss of some trailing bits in the fractional part.

I don't think the C++ standard guarantees that the result is correctly
rounded. Of course, it doesn't forbid that, either. Maybe contemporary
compilers are smart enough to fuse all the floating-point arithmetic
into one atomic operation.

>  Of course, after realizing that the difference in gcc behaviour was due to
> the difference in architecture, it didn't take me long to understand that
> this was due to using x87 floating point instructions in 32 bits. And,
> indeed, adding "-mfpmath=sse -msse2" to the compilation options makes all
> the check pass even when using MinGW 4.9.1 (I only tested it up to 8
> decimals though, as, without std::thread support that it lacks, anything
> beyond starts taking too long).
> 
>  I won't repeat the arguments I had already made (and even several times, I
> believe) for switching to the use of SSE instructions in lmi, but it's just
> clearly annoying to have different (and non-standard, without speaking of
                                          ^^^^^^^^^^^^ ?
> slower) behaviour in lmi code than with the other compilers/architectures.
> I realize switching to SSE is not a priority (and probably will never be),
> but it would still be nice to stop using x87.

"non-standard"? If my analysis above is incorrect, and the C++ standard
guarantees that the code above produces results identical to strtod(),
then please point out my mistake.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]