Boost logo

Boost :

From: Paul A Bristow (pbristow_at_[hidden])
Date: 2005-12-07 09:45:55


| -----Original Message-----
| From: boost-bounces_at_[hidden]
| [mailto:boost-bounces_at_[hidden]] On Behalf Of John Maddock
| Sent: 06 December 2005 18:40
| To: boost_at_[hidden]
| Subject: Re: [boost] [math] floating point classification -
| testinghelpwanted
|
| > Then for epsilon 2 ^-105 and 2 ^ -106 are below
| > outAsHex(one + numeric_limits<quad_float>::epsilon());
| > // 1.00000000000000000000000000000002 1 == 0x3ff0000000000000
| > 2.4651903288156619e-032 == 0x3960000000000000 2 ^-105
| > // 1.00000000000000000000000000000001 1==0x3ff0000000000000
| > 1.2325951644078309e-032==0x3950000000000000 2 ^ -106
| >
| > I note that the 2 ^ -106 value is the one I would naively expect - a
| > single least significant bit different.
|
| Strange!
|
| The docs do make it clear that this type is rather strange:

OK, at least there is no confusion about that!

| Ah, now hold on: when you print out your results, even if there is a 1 in
| the last binary digit *that doesn't mean there will be a 1 in the last
| hexadecimal or decimal digit*. Think about it, unless the number of
binary
| bits fit into a whole number of bytes, the last binary 1 may
| be in a 1, 2, 4 or 8 position in the last byte.

But the two values printed are the same in all threee representations,
quad_float, doubles hi and lo, and dougles as hex. so how are they failing
the comparison.
I've glanced at the quad_float operator> < and == and they look fine.

My primitive routine, growed like topsy, prints the hi and lo doubles in hex
separately, mapping so I don't quite follow how the hex display can not be a
true representation.
(Actually it would be much simpler to union the double to a _int64?) As you
call nextafter repeatedly, on double or quad_float, the bits roll up from
the back end as I would expect. (Nasty things happen when x.lo hits
numeric_limit<double>::max, but that's surely not he problem here?)

union dhex
{ // Used by void outAsHex(double)
        double d;
        unsigned short usa[4]; // Suits Intel 8087 FP P J Plauger C
Standard p 67.
};

void outAsHex(double d)
{ // displayAsHex
        dhex dd = {d}; // Initialise double dd.d = 0.0;
        // Assume Intel 8087 FP.
        // Standard C Library P J Plaguer p 67.
        char fill = cout.fill('0'); // Save.
        int fmtflags = cout.flags();
        int precision = cout.precision(2 + numeric_limits<double>::digits *
3010/10000); // max_digits10()
        cout << dec << dd.d << "==0x" << hex << right
                << setw(4) << dd.usa[3] // SCCC CCCC CCCC FFFF sign &
exponent.
                << setw(4) << dd.usa[2] // CCCC
                << setw(4) << dd.usa[1] // CCCC
                << setw(4) << dd.usa[0] // FFFF
                ;
                cout.flags(fmtflags); // Restore.
                cout.fill(fill);
                cout.precision(precision);
} // void outAsHex(double d)

void outAsHex(quad_float x)
{ // displayAsHex
        char fill = cout.fill('0');
        int fmtflags = cout.flags();
        int precision = cout.precision(2+numeric_limits<quad_float>::digits
* 3010/10000); // Save.
        cout << right << x << ' '; // 33 decimal digits autofloat format.
        outAsHex(x.hi); cout << ' '; outAsHex(x.lo); cout << endl; //
max_digits10 & hex formats.
        cout.flags(fmtflags); // Restore.
        cout.fill(fill);
        cout.precision(precision);
} // outAsHex(quad_float x)

I have checked a bit more, but still baffled -- and getting bored ;-)

BOOST_CHECK_SMALL((one + numeric_limits<quad_float>::epsilon()) - one,
epsilon); // Check epsilon with value 'by definition'
// absolute value of (one + numeric_limits<quad_float>::epsilon()) -
one{0.123259516440783094595582588325435e-31} exceeds
0.123259516440783094595582588325435e-31

Which is still bizarre.

outAsHex(one + numeric_limits<quad_float>::epsilon() - one); //
0.246519032881566189191165176650871e-31 2.4651903288156619e-032 ==
0x3960000000000000 0 == 0x0000000000000000
outAsHex(numeric_limits<quad_float>::epsilon()); //
0.246519032881566189191165176650871e-31
2.4651903288156619e-032==0x3960000000000000 0==0x0000000000000000

BOOST_CHECK((one + numeric_limits<quad_float>::epsilon()) != one); // Check
epsilon with value 'by definition' - pass
BOOST_CHECK((one + numeric_limits<quad_float>::epsilon()) >= one); // Check
epsilon with value 'by definition' - pass
BOOST_CHECK(one <= (one + numeric_limits<quad_float>::epsilon())); // Check
epsilon with value 'by definition' - pass

With the tolerance doubled

BOOST_CHECK_SMALL((one + numeric_limits<quad_float>::epsilon()) - one,
epsilon + epsilon); - pass

I conclude so far that this epsilon is a reasonable approximation to an
il--defined value and will _probably_ prove useful. I'm going to give up
and try it out.

| I actually tried to write a short program to calculate epsilon with this
| type, but quad_float exhibits some very strange behaviour:
<snip>
 | Double weird.

Quadruply weird!
 
A proper 128-bit FP would be MUCH nicer. (This sort of ill-behaviour is
probably why Keith Briggs, 'whose fault all this is ' ;-) now recommends
Exact Real http://keithbriggs.info/xrc.html) despite its lack of speed. Or
NTL RR where you can have enough decimal places to not worry about a few
dodgy ones. But then espilon is really meaningless?

Paul

-- 
Paul A Bristow
Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB
Phone and SMS text +44 1539 561830, Mobile and SMS text +44 7714 330204
mailto: pbristow_at_[hidden]  http://www.hetp.u-net.com/index.html
http://www.hetp.u-net.com/Paul%20A%20Bristow%20info.html

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk