double cast to int reliable?

S

spasmous

In the following code:

int i,j;
double d;

i = 1; /* or any integer */
d = (double)i;
j = (int)d;

Is there any chance that "i" will not equal "j" due to the double
being stored inexactly?
 
J

jacob navia

spasmous said:
In the following code:

int i,j;
double d;

i = 1; /* or any integer */
d = (double)i;
j = (int)d;

Is there any chance that "i" will not equal "j" due to the double
being stored inexactly?

If int is 32 bits no.
if int is more than 53 bits, yes definitely.

A IEEE double can hold 53 bits of precision
(without the exponent), so 32 bits will easily fit,
but not 64 or 55
 
S

spasmous

     Not for `i = 1', but for "any integer" the answer is "perhaps,
depending on the platform."

     By the way, both casts are superfluous.

--

This is a tricky problem. The function rint returns a double, which
may not be exactly an integer. So even j = (int)rint(d) is fallible.
Is there a standard function to round a double to an int that actually
returns an int?
 
U

user923005

In the following code:

int i,j;
double d;

i = 1; /* or any integer */
d = (double)i;
j = (int)d;

Is there any chance that "i" will not equal "j" due to the double
being stored inexactly?

What you are looking for is called floor().
It will return the integer part of any double as a double correctly.
See (for instance):
http://www.manpagez.com/man/3/floor/

Using integer assignment is asking for trouble.
Consider:
d = 1.0e65; /* This is an integer, but assigning this value to an
integer will result in undefined behavior on just about any system. */
d = 123456789012345.0; /* This is an integer, but the int assignment
won't work on systems with 32 bit int */

A bit of thought will show that for any value above INT_MAX or below
INT_MIN the int assignment idea fails.

The floor() function is designed for this exact purpose. Why not use
it?
 
B

Ben Bacarisse

This is a tricky problem. The function rint returns a double, which
may not be exactly an integer. So even j = (int)rint(d) is fallible.
Is there a standard function to round a double to an int that actually
returns an int?

Almost. lrint and llrint (and their Xrintf and Xrintl companions)
have return types that are integral but not actually 'int'. If the
result fits in an int, the conversion from long or long long to int
will be exact.
 
U

user923005

Almost.  lrint and llrint (and their Xrintf and Xrintl companions)
have return types that are integral but not actually 'int'.  If the
result fits in an int, the conversion from long or long long to int
will be exact.

If the OP is trying to achieve integer truncation then lrint() and
llrint() are not the correct functions to use since they perform
rounding.
(IOW, integer assignment in the acceptable range will perform
truncation and not rounding which seems to be the effect the OP is
after).
 
B

Ben Bacarisse

user923005 said:
If the OP is trying to achieve integer truncation then lrint() and
llrint() are not the correct functions to use since they perform
rounding.

Obviously. But since the OP wanted "to round a double to an int" and
did not like the return type of rint (which rounds as well) it seemed
a reasonable assumption!
 
F

Flash Gordon

spasmous said:
This is a tricky problem. The function rint returns a double, which
may not be exactly an integer. So even j = (int)rint(d) is fallible.
Is there a standard function to round a double to an int that actually
returns an int?

There isn't, but see the reply Jacob gave. If the result can be
represented as an exact integer it will be, and there are very few
implementations where the entire range of an int cannot be represented
exactly in a double.
 
J

jameskuyper

jacob said:
If int is 32 bits no.
if int is more than 53 bits, yes definitely.

A IEEE double can hold 53 bits of precision
(without the exponent), so 32 bits will easily fit,
but not 64 or 55

Unless an implementation chooses to pre-define the macro
__STDC_IEC_559__, the C standard imposes no obligation that double be
an IEEE type. The standard allows DBL_EPSILON to be as high as 1e-9.
Assuming FLT_RADIX==2, this allows for as few as 31 bits in the
significand, meaning that numbers as low as 2^32+1 might not be
exactly representable in double. int32_t is safe, but nothing larger
is.

And before you ask - yes, there are real-world programs that have to
deal with non-IEEE floating point formats. For instance, a program I
had to write recently forced me to become familiar with MIL-STD-1750A,
which specifies 32-bit and 48-bit floating point formats that don't
match IEEE requirements, but do meet the requirements of the C
standard. See <http://en.wikipedia.org/wiki/MIL-STD-1750A> for more
details. A link from that page leads to <http://www.xgc.com/products/
gcc-1750/gcc-1750.html>, a C compiler that supports those formats.
 
J

jameskuyper

spasmous said:
This is a tricky problem. The function rint returns a double, which
may not be exactly an integer.

The specification for rint() says that "The rint functions differ from
the nearbyint functions (7.12.9.3) only in that the rint functions may
raise the ‘‘inexact’’ floating-point exception if the result differs
in value from the argument." The specification for nearbyint() says
"The nearbyint functions round their argument to an integer value in
floating-point format". Therefore, neither function can return a non-
integral value, though the value is returned in a floating point type.
... So even j = (int)rint(d) is fallible.
Is there a standard function to round a double to an int that actually
returns an int?

Yes - lrint() and llrint(), lround() and llround().
 
J

jameskuyper

user923005 wrote:
....
If the OP is trying to achieve integer truncation then lrint() and
llrint() are not the correct functions to use since they perform
rounding.

The original question was about converting an integer to a floating
point type and back again. While the standard fails to say so, any
decent implementation will convert an integer to a floating point
value for which the difference between truncation and rounding is
irrelevant.
 
C

CBFalconer

jacob said:
If int is 32 bits no. if int is more than 53 bits, yes definitely.

A IEEE double can hold 53 bits of precision (without the
exponent), so 32 bits will easily fit, but not 64 or 55

Spasmous can investigate <limits.h> for his system, and examine the
values listed for MAX_DBL* and MAX_FLT* (or are they DBL_MAX
etc.?). At any rate, they will describe his systems capabilities.
 
E

Eric Sosman

spasmous said:
This is a tricky problem.

I'm not sure exactly what you mean by "this," nor
what trickiness you see in it.
The function rint returns a double, which
may not be exactly an integer.

The rint functions return a double that *is* exactly a
mathematical integer, but perhaps not a value representable
as `int' (or as any other C integer type, for that matter).
So even j = (int)rint(d) is fallible.

Garbage in, garbage out. rint(INT_MAX + 42.0) yields
an integer, but there's no reason you should expect to be
able to store that value in an `int'.
Is there a standard function to round a double to an int that actually
returns an int?

No. If there were, it would still be subject to the
limitation illustrated above.
 
C

CBFalconer

jameskuyper said:
.... snip ...

The original question was about converting an integer to a floating
point type and back again. While the standard fails to say so, any
decent implementation will convert an integer to a floating point
value for which the difference between truncation and rounding is
irrelevant.

Such a conversion cannot fail, since the input is an integer, and
no information is lost. Assuming the integral capacity of the
floating point is as large as the integer.
 
J

James Kuyper

CBFalconer said:
jameskuyper wrote:
... snip ...

Such a conversion cannot fail, since the input is an integer, and
no information is lost. Assuming the integral capacity of the
floating point is as large as the integer.

Yes - it would be nice if the standard had contained some words actually
making such a guarantee. What is has, instead, is 5.2.4.2.2p5, which says:

"The accuracy of the floating-point operations (+, -, *, /) and of the
library functions in <math.h> and <complex.h> that return floating-point
results is implementation defined, as is the accuracy of the conversion
between floating-point internal representations and string
representations performed by the library functions in <stdio.h>,
<stdlib.h>, and <wchar.h>. The implementation may state that the
accuracy is unknown."

You get better results if you restrict your comments to implementations
which predefine __STDC_IEC_559__; such implementations are required to
conform to IEEE/IEC 559, which imposes fairly strict accuracy
requirements on all floating point operations.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top