Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > C/C++ pitfalls related to 64-bits (unsigned long & double)

Reply
Thread Tools

C/C++ pitfalls related to 64-bits (unsigned long & double)

 
 
BGB
Guest
Posts: n/a
 
      02-13-2012
On 2/13/2012 6:16 AM, Ben Bacarisse wrote:
> Alex Vinokur<> writes:
>
> Talking from the C perspective here...
>
>> unsigned long a = -1;
>> double b = a;
>> unsigned long c = b;
>>
>> Model 32-bits: a == c
>> Model 64-bits: a != c
>>
>> It is not a compiler bug for 64-bits.

>
> Quite. Both outcomes are permitted.
>
>> Is it a design bug of C/C++ languge for 64-bits?

>
> No.
>
> Your use of "64-bits" is a little confusing. Not all 64-bit systems
> have 64 bit unsigned longs which is, I think, what you are talking
> about.
>
> On systems with 64-bit longs and standard 56-bit mantissa doubles, you
> can not represent ULONG_MAX (the value of 'a' in the above code) exactly
> in a double. C mandates that you get one of the two nearest
> representable values, but it wont be exact. When the conversion goes
> the other way the result can be undefined (if the floating point values
> was rounded up to a value larger that ULONG_MAX), but, even if the
> double has a value in the range of unsigned long, it will not longer
> equal ULONG_MAX.
>
> I said "no" to it being an error in the design of the language because
> solving it would impose the kind of burden on implementations that C
> rejects. C is designed to use native machine types wherever possible.
>


yeah.

also, even though double has more bits than, say, an integer, does not
mean it will reliably encode an integer's value (it can do so in theory,
and will most often do so, but whether or not it will actually always do
so is more "up for grabs").


it is much less reliable with float (since float has only about 23 bits
to hold an integer's value, vs the 52 bits or so in double).

hence, float can't reliably hold the entire integer range, and double
can't reliably hold the entire long-long range (the size of long is
target specific, even for the same CPU architecture and operating mode,
it may still vary between the OS and compiler in use).


the most common behavior seems to be:
int -> float or double, may produce a value slightly below the integer;
float or double to int, will generally truncate the value, yielding the
integer representation as rounded towards 0.

the result then is a tendency for an int->double->int conversion to have
a small chance to drop the integer value towards 0 (why? I don't know
exactly, but I have observed it before).

one can counteract this by fudging the value with a small epsilon prior
to converting back into an integer.

say, for example (untested, from memory):
(v>=0)?((int)(v+0.0001))(int)(v-0.0001));

can't say it will always work, but similar seems to work fairly well IME
(at least on generic x86 based targets).


or such...
 
Reply With Quote
 
 
 
 
Richard
Guest
Posts: n/a
 
      02-13-2012
[Please do not mail me a copy of your followup]

Alex Vinokur <> spake the secret code
<2d5ceb71-98bb-440a-be68-> thusly:

>unsigned long a = -1;


Isn't this undefined behavior right from the get-go?
--
"The Direct3D Graphics Pipeline" -- DirectX 9 version available for download
<http://legalizeadulthood.wordpress.com/the-direct3d-graphics-pipeline/>

Legalize Adulthood! <http://legalizeadulthood.wordpress.com>
 
Reply With Quote
 
 
 
 
James Kuyper
Guest
Posts: n/a
 
      02-13-2012
On 02/13/2012 01:49 PM, Richard wrote:
....
> Alex Vinokur <> spake the secret code
> <2d5ceb71-98bb-440a-be68-> thusly:
>
>> unsigned long a = -1;

>
> Isn't this undefined behavior right from the get-go?


No, why do you think so?

The behavior is defined by 6.3.1.3p2 in the C standard, which has been
quoted several times already in this thread. Do you have any reason to
doubt the accuracy or applicability of that section to this code, or
have you simply not been paying attention?
..
Since this is cross-posted comp.lang.c++, section 4.7p2 is the
appropriate location in the C++ standard; it says essentially the same
thing, but with different language.
 
Reply With Quote
 
Juha Nieminen
Guest
Posts: n/a
 
      02-13-2012
In comp.lang.c++ James Kuyper <> wrote:
> On 02/13/2012 01:49 PM, Richard wrote:
> ...
>> Alex Vinokur <> spake the secret code
>> <2d5ceb71-98bb-440a-be68-> thusly:
>>
>>> unsigned long a = -1;

>>
>> Isn't this undefined behavior right from the get-go?

>
> No, why do you think so?


Even if it were undefined, you could simply change it to:

unsigned long a = ~0UL;
 
Reply With Quote
 
Barry Schwarz
Guest
Posts: n/a
 
      02-13-2012
On Mon, 13 Feb 2012 04:41:44 -0800 (PST), Alex Vinokur
<> wrote:

>Hi,
>
>unsigned long a = -1;
>double b = a;
>unsigned long c = b;
>
>Model 32-bits: a == c
>Model 64-bits: a != c
>
>
>It is not a compiler bug for 64-bits.
>
>Is it a design bug of C/C++ languge for 64-bits?


It is simply an artifact of the number of significant digits in a
double and an unsigned long which I think the implementation must
document.

--
Remove del for email
 
Reply With Quote
 
MikeWhy
Guest
Posts: n/a
 
      02-13-2012
BGB wrote:
> ... even though double has more bits than, say, an integer, does not
> mean it will reliably encode an integer's value (it can do so in
> theory, and will most often do so, but whether or not it will
> actually always do so is more "up for grabs").


What circumstances are those? Integers hold integer values. AFAIK, all
integer values encode correctly in FP of higher precision. It's a simple
matter of normalization. (On Intel, a bit-scan operation.)



 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      02-13-2012
On 02/13/2012 04:18 PM, MikeWhy wrote:
> BGB wrote:
>> ... even though double has more bits than, say, an integer, does not
>> mean it will reliably encode an integer's value (it can do so in
>> theory, and will most often do so, but whether or not it will
>> actually always do so is more "up for grabs").

>
> What circumstances are those? Integers hold integer values. AFAIK, all
> integer values encode correctly in FP of higher precision. It's a simple
> matter of normalization. (On Intel, a bit-scan operation.)


You've covered the correct point, but have apparently not realized that
it was relevant. He'd talking about converting an integer value to a
floating point type when the floating point type has insufficient
precision to encode the value correctly. This is less than clear,
because he's making all kinds of implementation-specific assumptions
about the sizes of various types, and (inconsistently) using 'integer'
as if it were synonymous with 'int'.

The key point is that, for instance, a 32-bit integer type can represent
values too large to be converted without loss of precision to a 32-bit
floating point type, because the floating point type uses some of those
bits for the exponent. The same thing applies to 64 bit integer types
and and 64 bit floating point types.

 
Reply With Quote
 
glen herrmannsfeldt
Guest
Posts: n/a
 
      02-13-2012
In comp.lang.c++ Eric Sosman <> wrote:
> On 2/13/2012 8:14 AM, Eric Sosman wrote:
>> [...] Since hardware that offers 64 bits of precision in the
>> floating-point format used for `double', some loss of precision in
>> `b = a' must be expected.


> Oh, drat. There was supposed to be an "is fairly rare" just
> before the comma ...


x87 hardware isn't that rare. Depending on the implementation,
the compiler might do the calculation in temporary real form,
with all 64 bits.

But, yes, the usual double is 64 total bits, so fewer than 64
for the significand. As far as I know, though, there is no
restriction in C or C++ against a larger double, such as
a 64 bit float and 128 bit double.

-- glen
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      02-13-2012
BGB <> writes:
<snip>
> also, even though double has more bits than, say, an integer, does not
> mean it will reliably encode an integer's value (it can do so in
> theory, and will most often do so, but whether or not it will actually
> always do so is more "up for grabs").


It's not up for grabs in C (and C++ is essentially the same in this
regard). If the integer can be represented exactly in the floating
point type, it must be.

<snip>
> float or double to int, will generally truncate the value, yielding
> the integer representation as rounded towards 0.


That's true of the truncated value can be represented as an int. If
not, the behaviour is undefined. For example, in the example that
triggered this thread my implementation produces zero as the result.

> the result then is a tendency for an int->double->int conversion to
> have a small chance to drop the integer value towards 0 (why? I don't
> know exactly, but I have observed it before).


If the int is "in range" you don't have a conforming C implementation.

> one can counteract this by fudging the value with a small epsilon
> prior to converting back into an integer.
>
> say, for example (untested, from memory):
> (v>=0)?((int)(v+0.0001))(int)(v-0.0001));


I can't see how this helps. If v is representable exactly as a double,
the round trip has no effect so this code is not needed. Can you give me
a use-case?

> can't say it will always work, but similar seems to work fairly well
> IME (at least on generic x86 based targets).


--
Ben.
 
Reply With Quote
 
MikeWhy
Guest
Posts: n/a
 
      02-13-2012
James Kuyper wrote:
> On 02/13/2012 04:18 PM, MikeWhy wrote:
>> BGB wrote:
>>> ... even though double has more bits than, say, an integer, does not
>>> mean it will reliably encode an integer's value (it can do so in
>>> theory, and will most often do so, but whether or not it will
>>> actually always do so is more "up for grabs").

>>
>> What circumstances are those? Integers hold integer values. AFAIK,
>> all integer values encode correctly in FP of higher precision. It's
>> a simple matter of normalization. (On Intel, a bit-scan operation.)

>
> You've covered the correct point, but have apparently not realized
> that it was relevant. He'd talking about converting an integer value
> to a floating point type when the floating point type has insufficient
> precision to encode the value correctly. This is less than clear,
> because he's making all kinds of implementation-specific assumptions
> about the sizes of various types, and (inconsistently) using 'integer'
> as if it were synonymous with 'int'.
>
> The key point is that, for instance, a 32-bit integer type can
> represent values too large to be converted without loss of precision
> to a 32-bit floating point type, because the floating point type uses
> some of those bits for the exponent. The same thing applies to 64 bit
> integer types and and 64 bit floating point types.


Point taken, which is the OP point of 64-bit ULL in a 53 bit mantissa (or
32-bit int in a single precision float). This is easily understood and
documented for the architecture in numeric_limits. Still wondering here
about the "up for grabs" part. It seems to imply some edge condition that
isn't accounted for.


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
C/C++ pitfalls related to 64-bits (unsigned long & double) Alex Vinokur C++ 60 02-15-2012 08:00 AM
Having compilation error: no match for call to ‘(const __gnu_cxx::hash<long long int>) (const long long int&)’ veryhotsausage C++ 1 07-04-2008 05:41 PM
long long and long Mathieu Dutour C Programming 4 07-24-2007 11:15 AM
unsigned long long int to long double Daniel Rudy C Programming 5 09-20-2005 02:37 AM
Assigning unsigned long to unsigned long long George Marsaglia C Programming 1 07-08-2003 05:16 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57