473,395 Members | 1,931 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Strange behaviour of tiny double numbers

Hello,

two days ago I stumbled across a very strange problem that came up when
we were printing tiny double numbers as strings and trying to read them
on another place. This is part of an object serialisation framework
that cannot be done in binary format currently, so please no comments
about this ,-))

It took quite some time to shrink down the problem but it looks like
that C++ does not behave well in regards to very tiny numbers.
The <limits> header of the STL defines various templates that should
return amonst other things the tiniest negative double number that C++
can handle. The line

cout << numeric_limits<double>::min() << endl;

returns "2.22507e-308". So I would expect that every number closer to
zero (but still negative) would be treated as zero?

Please have a look at the following code snippet (insert it into a
"main" to run it on your compiler):
ostringstream output;
istringstream input;

// Regarding the limits this should assign zero to foobar, but it
doesn't look like that ?!?
double foobar = -2.345e-315;

// Simply put three numbers on the stream
output << 10 << " ";
output << 2.12345 << " ";
output << foobar << " ";
output << 10 << endl;

// Print out the resulting stream, you should see the above three
numbers
cout << output.str() << endl;

// Generate input stream from the output stream
input.str(output.str());

int int1=0, int2=0;
double double1=0, double2=0;

// For every read action print out the stream state
input >> int1;
cout << input.good() << endl;
input >> double1;
cout << input.good() << endl;

// Here comes the read of the "wrong" double
input >> double2;
cout << input.good() << endl;
input >> int2;
cout << input.good() << endl << endl;

// Now print out the numbers from the stream
cout << int1 << endl;
cout << double1 << endl;
cout << double2 << endl;
cout << int2 << endl;

Although I'm doing this example with three numbers only the 3rd number
is of interest as this number is a double value that should be zero
after the assignment from my understanding.

Various things come up when running the code that I cannot explain
currently:

1) The assignment obviously does not assign zero. Proof: Printing the
resulting stream yields "-2.345e-315" as the third number (checked on
..NET 2003 C++ and g++ 4.0/Linux). Why that?

2) The number is printed to the stream as "-2.345e-315". But regarding
<limits> this number should impossible to handle?

3) The accompanying read action results in different behavious
.NET 2003: input.good() toggles to "false" after read, the read
number "double2" is not read, subsequent reads fail.
g++ 4.0/Linux: The number is read, the stream state is "true",
subsequent numbers are read.

Why does this code work on g++? This should not run as the numeric
limit produces exactly the same number as with .NET2003

#3 currently produces the biggest headaches as in our current framework
this very tiny numbers are produces on linux servers but must be read
on windows clients. Following the above tests this cannot work.

So beside the basic question "What is the real limit of a double number
and why does this not work in c++?" there seems to be some platform
dependante implementations; what is the reason for this?
Thanks a lot for shedding some light in this issue,
Soeren Gerlach

Jun 18 '06 #1
5 4032
so****@all-about-shift.com wrote:
It took quite some time to shrink down the problem but it looks like
that C++ does not behave well in regards to very tiny numbers.
The <limits> header of the STL defines various templates that should
return amonst other things the tiniest negative double number that C++
can handle. The line

cout << numeric_limits<double>::min() << endl;

returns "2.22507e-308". So I would expect that every number closer to
zero (but still negative) would be treated as zero?


No. numeric_limits<double>::min() returns the minimum _normalized_ value.
There can be denormalized values which are closer to zero. This is very
likely the case here. You should try denorm_min() instead (gives me
4.94066e-324).

Even then smaller values may still be rounded up to denorm_min() (e.g.
2.5e-324 is rounded to denorm_min() but 2.4e-324 is rounded to 0).

Jun 18 '06 #2
so****@all-about-shift.com wrote:
cout << numeric_limits<double>::min() << endl;

returns "2.22507e-308". So I would expect that every number closer to
zero (but still negative) would be treated as zero?
Note that this is (a printed approximation) to the smallest /normal/
number.

The IEEE 754 double precision format allows for smaller magnitudes than
that, in the form of denormal numbers.

Note that the numeric_limits system has a denorm_min() function.
double foobar = -2.345e-315;


So here, you are in the territory of denormals. Denormals have the
smallest possible exponent, but the mantissa is interpreted as not
having the implicit leading 1.

You can think of zero as being a special case of the the denormals.

Or, conversely, as denormals being extensions to zero where the
mantissa bits are used to encode tiny values near to zero.

The smallest positive denormal (or, in alternate terminology,
subnormal) is approximately 4.94E-324. As you can see, this is quite a
bit smaller still than the denormal you are representing in your
program.

Jun 18 '06 #3
> It took quite some time to shrink down the problem but it looks like
that C++ does not behave well in regards to very tiny numbers.
The <limits> header of the STL defines various templates that should
return amonst other things the tiniest negative double number that C++
can handle. The line

cout << numeric_limits<double>::min() << endl;

returns "2.22507e-308". So I would expect that every number closer to
zero (but still negative) would be treated as zero?


numeric_limits<double>::min() returns the smallest
positive number representable. Maybe I don't understand
what you mean by "tiniest" but at any rate, min() returns
a positive number. albeit a very small one <g>
Jun 19 '06 #4
so****@all-about-shift.com wrote:
3) The accompanying read action results in different behavious
.NET 2003: input.good() toggles to "false" after read, the read
number "double2" is not read, subsequent reads fail.
g++ 4.0/Linux: The number is read, the stream state is "true",
subsequent numbers are read.

#3 currently produces the biggest headaches as in our current framework
this very tiny numbers are produces on linux servers but must be read
on windows clients. Following the above tests this cannot work.


Sounds like you need an immediate work-around for the Windows bug.
(This is unquestionably a bug. A number that it can write should not
kill a read.)

I suggest reading the number as a string, then converting to double in
a separate step so even if that has a bug, you can continue with a
close substitute value (such as zero). It's fairly unlikely that you
need to pass these values accurately since they are in the range of
denormalized numbers, where gradual underflow causes loss of precision.
Jun 19 '06 #5
Hi all,

okay, with this mailthread I learned a lot about the denormal numbers
,-))

I tested it today on two other environments (linux 2.4 + icc 8.0 /
Solaris 5.8 + gcc 2.95) and the test program doesn't fail on these
environmets as it did not fail on Linux 2.4 + gcc 4). Obviously this
seems to be MSVC related so nothing for this newsgroup.
Thanks a lot for your help,
Soeren Gerlach

Jun 19 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
by: Allcomp | last post by:
Hello, I have seen something really strange in VB6 If I do a Int ( (5 * 1.2)) , I receive the value 5, but I should receive 6? Is this a bug or something really "normal". I can see that if I...
7
by: Colin Brown | last post by:
Python 2.3.3 Under Windows NT: Negative Int or Real -> sleeps for a long time Under Linux: Returns IOError: Invalid argument I consider both of these unfriendly results and expected the...
24
by: David | last post by:
hello. when doing the simple following computation, the value put into the variable numMinusOne is NOT the same as what the computation is showed to be in the Watch window!! here is the code:...
10
by: bear | last post by:
hi all, I have a program whose speed is so strange to me. It is maily used to calculate a output image so from four images s0,s1,s2,s3 where so=(s0-s2)^2+ (s1-s3)^2. I compile it with gcc (no...
3
by: Norvin Laudon | last post by:
Hi, Can somebody explain the following, from the MSDN documentation for the "System.Convert.ToInt32(double)" function <quote> Return Value value rounded to the nearest 32-bit signed...
2
by: Chris | last post by:
Hi, a strange behaviour when working with exceptions : when I divide and integer by 0 will an exception be thrown. OK but, when I divide a double by 0 is no exception thrown ??? How come ? ...
1
by: Chris | last post by:
Hi, a strange behaviour when working with exceptions : when I divide and integer by 0 will an exception be thrown. OK but, when I divide a double by 0 is no exception thrown ??? How come ? ...
10
by: Michele | last post by:
Please forgive me for the neverending code down here but I cannot find a rational explanation of the output of this simple program (really!). Soluzione class has a double field to represent a...
8
by: Henrik Skak Pedersen | last post by:
Hi, I have the following very simple code snippet: line 1: float f; line 2: f = 100000.99f; Why is f: 100000.992 after line 2? I would assume it to be 100000.99. Cheers
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.