Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to determine if double contains an integer value?

11 views
Skip to first unread message

DeCaf

unread,
Oct 29, 2006, 11:30:52 PM10/29/06
to
Hi,

I'm wondering if there is a "correct" way to check if a double (or any
other floating point type) contains an integer value?

I was thinking along the way of:

bool is_integer(double d)
{
return (d - (int)d) == 0.0;
}

But since I'm not too good at floating point arithmetic, I'm not sure
if this would work in 100% of the cases. Does anyone know if this will
always work, or is there a better way of performing this check?

Sincerely, Peter


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Greg Herlihy

unread,
Oct 30, 2006, 1:39:20 AM10/30/06
to
DeCaf wrote:
> Hi,
>
> I'm wondering if there is a "correct" way to check if a double (or any
> other floating point type) contains an integer value?
>
> I was thinking along the way of:
>
> bool is_integer(double d)
> {
> return (d - (int)d) == 0.0;
> }
>
> But since I'm not too good at floating point arithmetic, I'm not sure
> if this would work in 100% of the cases. Does anyone know if this will
> always work, or is there a better way of performing this check?

I think a better way to determine whether a double represents an exact
integral value would be to compare the value modulo 1.0 against zero,
like so:

if ( std::fmod( d, 1.0) == 0.0)
{
// integer value
}

Greg

Seungbeom Kim

unread,
Oct 30, 2006, 3:21:54 AM10/30/06
to
DeCaf wrote:
> Hi,
>
> I'm wondering if there is a "correct" way to check if a double (or any
> other floating point type) contains an integer value?
>
> I was thinking along the way of:
>
> bool is_integer(double d)
> {
> return (d - (int)d) == 0.0;
> }
>
> But since I'm not too good at floating point arithmetic, I'm not sure
> if this would work in 100% of the cases. Does anyone know if this will
> always work, or is there a better way of performing this check?

(int)d suffers from a possible overflow - the integral portion of d
might not be representable in an int. Using floor(d) seems better.

You might also want to consider allowing a small amount of error:

bool is_integer(double d)
{
return fabs(d - floor(d)) < 1e-6; // for example
}

--
Seungbeom Kim

Alberto Ganesh Barbati

unread,
Oct 30, 2006, 5:43:53 AM10/30/06
to
Greg Herlihy ha scritto:

> DeCaf wrote:
>> Hi,
>>
>> I'm wondering if there is a "correct" way to check if a double (or any
>> other floating point type) contains an integer value?
>>
>> I was thinking along the way of:
>>
>> bool is_integer(double d)
>> {
>> return (d - (int)d) == 0.0;
>> }
>>
>> But since I'm not too good at floating point arithmetic, I'm not sure
>> if this would work in 100% of the cases. Does anyone know if this will
>> always work, or is there a better way of performing this check?
>
> I think a better way to determine whether a double represents an exact
> integral value would be to compare the value modulo 1.0 against zero,
> like so:
>
> if ( std::fmod( d, 1.0) == 0.0)
> {
> // integer value
> }
>

I think using std::modf can be even better.

Ganesh

Seungbeom Kim

unread,
Oct 30, 2006, 10:05:00 AM10/30/06
to
Seungbeom Kim wrote:
>
> (int)d suffers from a possible overflow - the integral portion of d
> might not be representable in an int. Using floor(d) seems better.
>
> You might also want to consider allowing a small amount of error:
>
> bool is_integer(double d)
> {
> return fabs(d - floor(d)) < 1e-6; // for example
> }

My mistake here; this actually depends on the sign of the error.
For example, if is_integer(d) will return false for d == 3 - 1e-7 or
d == -3 - 1e-7, contrary to my intent.

A quick fix is to replace floor() with round() (available in C99).

Jiang

unread,
Oct 30, 2006, 10:40:09 AM10/30/06
to

DeCaf wrote:
> Hi,
>
> I'm wondering if there is a "correct" way to check if a double (or any
> other floating point type) contains an integer value?
>

Sorry but what do you mean a double "contains" an integer?
Even you can round a double to a mathematical integer,
it is quite possible that the integer is beyond the
numeric_limits<int>::max() .

> I was thinking along the way of:
>
> bool is_integer(double d)
> {
> return (d - (int)d) == 0.0;
> }
>


Floating point comparison is one issue but if the floating point
types to integral types cast is considered unsafe. If the double
could not be casted into the range of integer, then the
behavior is undefined. IMHO, casting a floating number to integer
is not trivial at all.


> But since I'm not too good at floating point arithmetic, I'm not sure
> if this would work in 100% of the cases. Does anyone know if this will
> always work, or is there a better way of performing this check?
>

If you are really doing numeric casting, then maybe you should
check Boost::numeric_cast.

For example, Boost::numeric_cast throws correct overflow
exception for following ill-formed code.

#include <boost/numeric/conversion/cast.hpp>
#include <boost/numeric/conversion/converter_policies.hpp>
#include <iostream>

int main()
{
using boost::numeric_cast;
using boost::numeric::bad_numeric_cast;
using boost::numeric::positive_overflow;
using boost::numeric::negative_overflow;

try {

double a = 0.;
double b = 1.;
int i = numeric_cast<int>(b/a);

}
catch(bad_numeric_cast& e) {
std::cout << e.what();
}

return 0;
}

$ ./nc
bad numeric conversion: positive overflow

$

HTH

DeCaf

unread,
Oct 30, 2006, 11:09:09 AM10/30/06
to
Thank you all for replying. It does indeed seem as if std::modf does
pretty much everything I want, so if I do not want to allow for any
"small" amount of error, if I understood things correctly the following
function ought to do the trick:

bool is_integer(double d)
{
double p;
std::modf(d, &p);
return d == 0.0;
}

When it comes to std::fmod though, TC++PL 3rd Ed. says that it returns
the "floating-point remainder, same sign as d" (where d is the first
argument). Now, what is a floating point remainder?

Sincerely, Peter

On Oct 30, 11:43 am, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
wrote:

Martin Eisenberg

unread,
Oct 30, 2006, 11:07:06 AM10/30/06
to
Alberto Ganesh Barbati wrote:
> Greg Herlihy ha scritto:
>> DeCaf wrote:

>>> I'm wondering if there is a "correct" way to check if a double
>>> (or any other floating point type) contains an integer value?
>>>
>>> I was thinking along the way of:
>>>
>>> bool is_integer(double d)
>>> {
>>> return (d - (int)d) == 0.0;
>>> }

>> I think a better way to determine whether a double represents


>> an exact integral value would be to compare the value modulo
>> 1.0 against zero, like so:
>>
>> if ( std::fmod( d, 1.0) == 0.0)
>> {
>> // integer value
>> }
>
> I think using std::modf can be even better.

I'm asking both of you -- why?


Martin

--
Quidquid latine scriptum sit, altum viditur.

Greg Herlihy

unread,
Oct 30, 2006, 12:01:37 PM10/30/06
to
DeCaf wrote:
> Thank you all for replying. It does indeed seem as if std::modf does
> pretty much everything I want, so if I do not want to allow for any
> "small" amount of error, if I understood things correctly the following
> function ought to do the trick:
>
> bool is_integer(double d)
> {
> double p;
> std::modf(d, &p);
> return d == 0.0;
> }
>
> When it comes to std::fmod though, TC++PL 3rd Ed. says that it returns
> the "floating-point remainder, same sign as d" (where d is the first
> argument). Now, what is a floating point remainder?

Exactly what one would expect it to be: a floating point remainder is
the (floating point) value that is "left over" after the divisor has
"gone into" the dividend an integral number of times.

For example: the floating pointer remainder of 5.0/2.0 is 1.0 (because
2.0 goes into 5.0 two times with 1.0 left over as the remainder),
Similarly, the floating point remainder of 2.75/0.5 is 0.25 (0.5 goes
into 2.75 five times with 0.25 remaining). A remainder of 0 always
means that the dividend is an exact multiple of the divisor. And since
all integers are exact multiples of 1.0, a zero remainder after
dividing a value by 1.0 must mean that the dividend value is an
integer.

Greg

Alberto Ganesh Barbati

unread,
Oct 30, 2006, 2:13:40 PM10/30/06
to
Martin Eisenberg ha scritto:

> Alberto Ganesh Barbati wrote:
>> Greg Herlihy ha scritto:
>>> DeCaf wrote:
>
>>>> I'm wondering if there is a "correct" way to check if a double
>>>> (or any other floating point type) contains an integer value?
>>>>
>>>> I was thinking along the way of:
>>>>
>>>> bool is_integer(double d)
>>>> {
>>>> return (d - (int)d) == 0.0;
>>>> }
>
>>> I think a better way to determine whether a double represents
>>> an exact integral value would be to compare the value modulo
>>> 1.0 against zero, like so:
>>>
>>> if ( std::fmod( d, 1.0) == 0.0)
>>> {
>>> // integer value
>>> }
>> I think using std::modf can be even better.
>
> I'm asking both of you -- why?

"d - (int)d" will produce undefined behavior if d can't be represented
in a int. Even if you use long you can't be sure.

Ganesh

--

Frederick Gotham

unread,
Oct 30, 2006, 5:35:36 PM10/30/06
to
Alberto Ganesh Barbati:

<Context: "d" is a double>

> "d - (int)d" will produce undefined behavior if d can't be represented
> in a int.


Are you sure it simply isn't implementation-defined?

--

Frederick Gotham

Martin Eisenberg

unread,
Oct 30, 2006, 5:35:09 PM10/30/06
to
Alberto Ganesh Barbati wrote:
> Martin Eisenberg ha scritto:
>> Alberto Ganesh Barbati wrote:
>>> Greg Herlihy ha scritto:

>>>> I think a better way to determine whether a double represents


>>>> an exact integral value would be to compare the value modulo
>>>> 1.0 against zero, like so:
>>>>
>>>> if ( std::fmod( d, 1.0) == 0.0)
>>>> {
>>>> // integer value
>>>> }
>>> I think using std::modf can be even better.
>>
>> I'm asking both of you -- why?
>
> "d - (int)d" will produce undefined behavior if d can't be
> represented in a int. Even if you use long you can't be sure.

Thanks -- but that's not a limitation of Greg's suggestion. Why is
modf better than fmod?


Martin

--
Quidquid latine scriptum sit, altum viditur.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Greg Herlihy

unread,
Oct 30, 2006, 5:36:05 PM10/30/06
to
Martin Eisenberg wrote:
> Alberto Ganesh Barbati wrote:
> > Greg Herlihy ha scritto:
> >> DeCaf wrote:
>
> >>> I'm wondering if there is a "correct" way to check if a double
> >>> (or any other floating point type) contains an integer value?
> >>>
> >>> I was thinking along the way of:
> >>>
> >>> bool is_integer(double d)
> >>> {
> >>> return (d - (int)d) == 0.0;
> >>> }
>
> >> I think a better way to determine whether a double represents
> >> an exact integral value would be to compare the value modulo
> >> 1.0 against zero, like so:
> >>
> >> if ( std::fmod( d, 1.0) == 0.0)
> >> {
> >> // integer value
> >> }
> >
> > I think using std::modf can be even better.
>
> I'm asking both of you -- why?

A direct solution to a problem is always superior to an indirect
solution, that is, a solution produced as the byproduct of an otherwise
completely unnecessary and unrelated operation.

Assigning a floating point value to an int variable is not the purpose
of the routine we have been asked to write - testing whether a floating
point value is exactly divisible by 1.0 - on the other hand - is the
problem we need to solve. And as it happens there are (at least) two
standard functions that can provide the needed answer - either of which
will do so reliably.

The problem with the indirect solution it that it creates an unneeded
dependency: the correctness of the result is tied to the successful
outcome of the unnecessary operation. In this case, the return result
will be correct only when testing those floating points values that
have defined int value representations. But of course whether a
particular floating point value has a corresponding representation as
an int in C++ - is a question whose answer has no bearing whatsoever on
the question of whether that same floating point value is an exact
multiple of 1.0.

Greg


--

Alberto Ganesh Barbati

unread,
Oct 31, 2006, 12:56:33 AM10/31/06
to
Frederick Gotham ha scritto:

> Alberto Ganesh Barbati:
>
> <Context: "d" is a double>
>
>> "d - (int)d" will produce undefined behavior if d can't be represented
>> in a int.
>
>
> Are you sure it simply isn't implementation-defined?
>

§4.9/1: "An rvalue of a floating point type can be converted to an
rvalue of an integer type. The conversion truncates; that is, the
fractional part is discarded. The behavior is undefined if the truncated
value cannot be represented in the destination type."

Ganesh

--

Alberto Ganesh Barbati

unread,
Oct 31, 2006, 12:57:04 AM10/31/06
to
Martin Eisenberg ha scritto:
> Alberto Ganesh Barbati wrote:
>> Martin Eisenberg ha scritto:
>>> Alberto Ganesh Barbati wrote:
>>>> Greg Herlihy ha scritto:
>
>>>>> I think a better way to determine whether a double represents
>>>>> an exact integral value would be to compare the value modulo
>>>>> 1.0 against zero, like so:
>>>>>
>>>>> if ( std::fmod( d, 1.0) == 0.0)
>>>>> {
>>>>> // integer value
>>>>> }
>>>> I think using std::modf can be even better.
>>> I'm asking both of you -- why?
>> "d - (int)d" will produce undefined behavior if d can't be
>> represented in a int. Even if you use long you can't be sure.
>
> Thanks -- but that's not a limitation of Greg's suggestion. Why is
> modf better than fmod?
>

The algorithm used by fmod is more general than modf as it can evaluate
the remainder of the division by any non-zero number, not just 1.0.
Therefore I expect the implementation of modf to be not worse than fmod,
while there is a slight chance that it might be more optimized and
perform better. Moreover, modf might return the integer part in one
single operation, if needed.

Ganesh

--

Jiang

unread,
Oct 31, 2006, 1:23:28 AM10/31/06
to
Greg Herlihy wrote:
> Martin Eisenberg wrote:

[snip]


>
> Assigning a floating point value to an int variable is not the purpose
> of the routine we have been asked to write - testing whether a floating
> point value is exactly divisible by 1.0 - on the other hand - is the
> problem we need to solve. And as it happens there are (at least) two
> standard functions that can provide the needed answer - either of which
> will do so reliably.
>


I am not sure they are reliable for decimal floating literals or not,
and I tested your method.

$ cat fmod.cpp

#include <cmath>
#include <iostream>

int main()
{
double d = 1.0000000000000001;

if(std::fmod(d,1.0) == 0.0){
std::cout << "exact division\n";
}else{
std::cout << "not exact division\n";
}

}

$ ./fmod
exact division

$

Is it the problem of double value representation? Or, the comprison
is not reliable?

Jack Klein

unread,
Oct 31, 2006, 1:22:06 AM10/31/06
to
On 30 Oct 2006 17:35:36 -0500, Frederick Gotham <fgot...@SPAM.com>
wrote in comp.lang.c++.moderated:

> Alberto Ganesh Barbati:
>
> <Context: "d" is a double>
>
> > "d - (int)d" will produce undefined behavior if d can't be represented
> > in a int.
>
>
> Are you sure it simply isn't implementation-defined?

Absolutely, positively sure.

Converting a floating point type to an integer type produces undefined
behavior if the value of the floating point type is outside the range
of the integer type. This is true even when the destination integer
type is unsigned, unlike the case when a higher rank integer type is
converted to a lesser rank unsigned type.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html

Seungbeom Kim

unread,
Oct 31, 2006, 8:56:10 AM10/31/06
to
Jiang wrote:
>
> $ cat fmod.cpp
>
> #include <cmath>
> #include <iostream>
>
> int main()
> {
> double d = 1.0000000000000001;
>
> if(std::fmod(d,1.0) == 0.0){
> std::cout << "exact division\n";
> }else{
> std::cout << "not exact division\n";
> }
>
> }
>
> $ ./fmod
> exact division
>
> $
>
> Is it the problem of double value representation? Or, the comprison
> is not reliable?

When I inspected the representation of d, it was exactly the same
as another double variable which was assigned exactly 1.0.
(3F F0 00 00 00 00 00 00 in big-endian)

On that system, std::numeric_limits<double>::epsilon() was 2.22045e-16,
which is greater than the difference between 1.0 and d, 1e-16. Therefore
adding 1e-16 to 1.0 doesn't change the value.

If you assign 1.0000000000000003 to d instead, you may see the output
"not exact division".

--
Seungbeom Kim

Greg Herlihy

unread,
Oct 31, 2006, 8:58:03 AM10/31/06
to

The program is producing the correct result given the values and the
floating point types used in its calculations. Now if the programmer is
expecting a different result, then the programmer is simply expecting a
greater degree of resolution than this program's double type can
provide. In particular, two floating point values must differ by at
least numeric_limits<double>::epsilon in order to ensure that the
compiler will recognize them as distinct double values. By the same
token, any two floating values that differ by less than epsilon are
likely to resolve to the same double value - as this programm
demonstrates.

The reason that this program may be reporting the "wrong" result is
simply that the difference between 1.0000000000000001 and 1.0 is only
1.0e-16 - or less than half of 2.22e-16 (which is the value of a
double's epsilon on most computers). Therefore this program resolves
1.0000000000000001 and 1.0 to same double value: 1.0. And 1.0 is an
integer value.

Now it might be helpful were the compiler to warn whenever the
specified value of a floating point literal exceeds the precision of
its type - but a C++ compiler is not obligated to do so. As long as the
specified value lies within (and not beyond) the range of representable
values for the type, the compiler is free to round to the closest
larger or the closest smaller value (in an implementation-defined
manner).

So without much in the way of help to be expected from the compiler in
this kind of situation, it is really up to the programmer to use
numeric_limits to check that the precision of a program's floating
point calculations is at least able to match the degree of precision
expected from them.

Greg

Alberto Ganesh Barbati

unread,
Oct 31, 2006, 8:56:56 AM10/31/06
to
Jiang ha scritto:

>
> #include <cmath>
> #include <iostream>
>
> int main()
> {
> double d = 1.0000000000000001;
>
> if(std::fmod(d,1.0) == 0.0){
> std::cout << "exact division\n";
> }else{
> std::cout << "not exact division\n";
> }
>
> }
>
> $ ./fmod
> exact division
>
> $
>
> Is it the problem of double value representation? Or, the comprison
> is not reliable?
>
>

The former. As log2(0.0000000000000001) is about -53.15, in order to
correctly represent 1.0000000000000001 in base-2 floating point you need
at least 54 bits of mantissa. However, typical implementations of double
(for example on ix86 machines) only use 53 bits. So when you load
1.0000000000000001 into d, you are actually storing 1.

However, the comparison is a big point of weakness of the algorithm. If
you assign to d an integral expression such as in:

double d = 1000;

then you can be reasonably sure that the fractional part is zero.
However, if d is the result of a floating-point valued expression such as:

double d = 1000.f / 10.f;

then you can't be be sure that the fractional part is *exactly* zero due
to rounding errors. You should always check floating point values with
<, <=, > or >=. Using == and != for floating point is looking for
trouble. Unfortunately, the naive implementation:

// wrong implementation!
bool is_integer(double d, double epsilon = 0.0000001)
{
return fabs(modf(d, 0)) < epsilon;
// alternatively: fabs(fmod(d, 1.0)) < epsilon
}

will produce incorrect results, because:

modf(1.0000001, 0) == 0.0000001
modf(1.0000000, 0) == 0.0000000
modf(0.9999999, 0) == 0.9999999

a more correct way is:

bool is_integer(double d, double epsilon = 0.0000001)
{
double f = modf(d, 0); // or fmod(d, 1.0)
return f < epsilon || 1.0 - f > epsilon;
}

Notice that you would have the same problem with "d - (int)d", because
the conversion from double to int truncates towards zero (§4.9/1).

HTH,

Ganesh

Martin Eisenberg

unread,
Oct 31, 2006, 9:00:38 AM10/31/06
to
Jiang wrote:

> #include <cmath>
> #include <iostream>
>
> int main()
> {
> double d = 1.0000000000000001;
>
> if(std::fmod(d,1.0) == 0.0){
> std::cout << "exact division\n";
> }else{
> std::cout << "not exact division\n";
> }
> }
>
> $ ./fmod
> exact division
>
> $
>
> Is it the problem of double value representation? Or, the
> comprison is not reliable?

As written d is supposed to equal 1 + 1e-16, but
std::numeric_limits<double>::epsilon() is greater than 2e-16 under
IEEE 754, so the compiler stores 1.0 in d.


Martin

--
Quidquid latine scriptum sit, altum viditur.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

James Kanze

unread,
Oct 31, 2006, 9:27:43 AM10/31/06
to
DeCaf wrote:

> Thank you all for replying. It does indeed seem as if std::modf does
> pretty much everything I want, so if I do not want to allow for any
> "small" amount of error, if I understood things correctly the following
> function ought to do the trick:

> bool is_integer(double d)
> {
> double p;
> std::modf(d, &p);
> return d == 0.0;
> }

Not quite. To begin with, modf doesn't modify its first
parameter. (It can't, since it is a C function, and can't take
a reference.) What you want is:

bool
is_integer( double d )
{
double dummy ;
return modf( d, &dummy ) == 0.0 ;
}

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Earl Purple

unread,
Oct 31, 2006, 9:29:37 AM10/31/06
to

DeCaf wrote:
> Hi,
>
> I'm wondering if there is a "correct" way to check if a double (or any
> other floating point type) contains an integer value?
>
> I was thinking along the way of:
>
> bool is_integer(double d)
> {
> return (d - (int)d) == 0.0;
> }
>
> But since I'm not too good at floating point arithmetic, I'm not sure
> if this would work in 100% of the cases. Does anyone know if this will
> always work, or is there a better way of performing this check?

How about floor( d ) == ceil( d ) ?

James Kanze

unread,
Oct 31, 2006, 9:29:05 AM10/31/06
to
Martin Eisenberg wrote:
> Alberto Ganesh Barbati wrote:
> > Martin Eisenberg ha scritto:
> >> Alberto Ganesh Barbati wrote:
> >>> Greg Herlihy ha scritto:

> >>>> I think a better way to determine whether a double represents
> >>>> an exact integral value would be to compare the value modulo
> >>>> 1.0 against zero, like so:

> >>>> if ( std::fmod( d, 1.0) == 0.0)
> >>>> {
> >>>> // integer value
> >>>> }
> >>> I think using std::modf can be even better.

> >> I'm asking both of you -- why?

> > "d - (int)d" will produce undefined behavior if d can't be
> > represented in a int. Even if you use long you can't be sure.

> Thanks -- but that's not a limitation of Greg's suggestion. Why is
> modf better than fmod?

Because it is designed to do exactly what is wanted. fmod is a
more general function. Because someone familiar with C or C++,
on reading the code, would automatically wonder why fmod was
being used, when modf is so obvious.

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


--

Jiang

unread,
Oct 31, 2006, 9:28:31 AM10/31/06
to

On Oct 31, 12:05 am, Seungbeom Kim <musip...@bawi.org> wrote:
> Seungbeom Kim wrote:
>
> > (int)d suffers from a possible overflow - the integral portion of d
> > might not be representable in an int. Using floor(d) seems better.
>
> > You might also want to consider allowing a small amount of error:
>
> > bool is_integer(double d)
> > {
> > return fabs(d - floor(d)) < 1e-6; // for example
> > }My mistake here; this actually depends on the sign of the error.
> For example, if is_integer(d) will return false for d == 3 - 1e-7 or
> d == -3 - 1e-7, contrary to my intent.
>
> A quick fix is to replace floor() with round() (available in C99).
>

But what is the rationale for choosing eps as a
magic number 1e-6?

And, for your example, it is strange that a floating
point number 2.9999999 *contains* a integer 3, well,
if we use FE_TONEAREST flag.


--

James Kanze

unread,
Oct 31, 2006, 9:30:34 AM10/31/06
to
Jiang wrote:
> Greg Herlihy wrote:
> > Martin Eisenberg wrote:

> [snip]

> > Assigning a floating point value to an int variable is not the purpose
> > of the routine we have been asked to write - testing whether a floating
> > point value is exactly divisible by 1.0 - on the other hand - is the
> > problem we need to solve. And as it happens there are (at least) two
> > standard functions that can provide the needed answer - either of which
> > will do so reliably.

> I am not sure they are reliable for decimal floating literals or not,

You can't apply them directly to a decimal floating point
literal, only to a double. (Versions for float are also
available.)

> and I tested your method.

> $ cat fmod.cpp

> #include <cmath>
> #include <iostream>

> int main()
> {
> double d = 1.0000000000000001;

I don't know about your machine, but on the machines I currently
have access to, this initializes d with the exact value 1.0.
Which is the closest representable value to the value you have
written.

> if(std::fmod(d,1.0) == 0.0){
> std::cout << "exact division\n";
> }else{
> std::cout << "not exact division\n";
> }
> }

> $ ./fmod
> exact division
> $

> Is it the problem of double value representation?

I'd say that it's more a problem with your understanding of what
a double is. It's a characteristic of the double
representation, but whether it is a problem or not depends on
what you are trying to do.

> Or, the comprison is not reliable?

For all intents and purposes, I would say that if the test
didn't work, it was a bug in the library. Technically speaking,
the standard doesn't require any minimum precision for the
functions in <math.h> (and I once encountered an implementation
where sin(x) gave results with less than 5 decimal digits of
precision), but from a QoI point of view, I can't see any
reasonable implemenation failing in this case.

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Earl Purple

unread,
Oct 31, 2006, 9:30:05 AM10/31/06
to

Seungbeom Kim wrote:

> > You might also want to consider allowing a small amount of error:
> >
> > bool is_integer(double d)
> > {
> > return fabs(d - floor(d)) < 1e-6; // for example
> > }
>
> My mistake here; this actually depends on the sign of the error.
> For example, if is_integer(d) will return false for d == 3 - 1e-7 or
> d == -3 - 1e-7, contrary to my intent.
>
> A quick fix is to replace floor() with round() (available in C99).
>
> --
> Seungbeom Kim

It also uses an absolute tolerance rather than a relative one. Better
is

bool is_integer( double d )
{

return (d == 0.0) || fabs(d / round( d ) - 1.0) < tol;
}

(obviously you decide what tol is an ensure round is implemented for
C++)


--

Jiang

unread,
Oct 31, 2006, 11:07:14 AM10/31/06
to
Greg Herlihy wrote:
> Jiang wrote:

[snip]

>
> The program is producing the correct result given the values and the
> floating point types used in its calculations. Now if the programmer is
> expecting a different result, then the programmer is simply expecting a
> greater degree of resolution than this program's double type can
> provide. In particular, two floating point values must differ by at
> least numeric_limits<double>::epsilon in order to ensure that the
> compiler will recognize them as distinct double values. By the same
> token, any two floating values that differ by less than epsilon are
> likely to resolve to the same double value - as this programm
> demonstrates.
>
> The reason that this program may be reporting the "wrong" result is
> simply that the difference between 1.0000000000000001 and 1.0 is only
> 1.0e-16 - or less than half of 2.22e-16 (which is the value of a
> double's epsilon on most computers). Therefore this program resolves
> 1.0000000000000001 and 1.0 to same double value: 1.0. And 1.0 is an
> integer value.
>


I found the same explanation soon after my above post, for my
current implementation, the difference smaller than 2.2e-16 (2 ^ -52)
could not be represented.

But frankly speaking I am still confused by the your statement
contains the word "exactly" :

" ...whether a floating point value is exactly divisible by 1.0 ..."

I checked the IEEE754, it does describe some behaviors for
how to evaluate the exact results. However, I failed to find the
decimal division/multiplication there.

BTW, if I switch to other implementation using different
epsilon (for example, intel x87 (epsilon == 2 ^ -63) ), then
I will get different result. Also currently not all compilers
support IEEE 754.

So, maybe divided by 1.0 is special, but I am still not sure
using the methods you and Ganesh purposed I will get the
reliable exact results or not.


> Now it might be helpful were the compiler to warn whenever the
> specified value of a floating point literal exceeds the precision of
> its type - but a C++ compiler is not obligated to do so. As long as the
> specified value lies within (and not beyond) the range of representable
> values for the type, the compiler is free to round to the closest
> larger or the closest smaller value (in an implementation-defined
> manner).
>


Yes, the IEEE standard does have the INEXACT trap purposed,
but most of the compilers just select to ignore it.


> So without much in the way of help to be expected from the compiler in
> this kind of situation, it is really up to the programmer to use
> numeric_limits to check that the precision of a program's floating
> point calculations is at least able to match the degree of precision
> expected from them.
>


Agreed.

At least we should add the numeric_limits checking to the above
two methods.

Carlos Moreno

unread,
Oct 31, 2006, 1:58:17 PM10/31/06
to
Greg Herlihy wrote:

>>argument). Now, what is a floating point remainder?
>
> Exactly what one would expect it to be: a floating point remainder is
> the (floating point) value that is "left over" after the divisor has
> "gone into" the dividend an integral number of times.

You could phrase it a bit more formally (mathematically speaking) as:

Given real numbers x and y, the floating-point remainder when dividing
x by y is the number r that meets the condition x = k*y + r, where k
is the integer with highest absolute value that meets that condition
with r restricted to having the same sign as x.

(hmmm, not sure if it works for all possible combinations of positive
and negative values for x and y ... I think it does... Oh well, it
should give the OP an idea, although the intuitive way you put it
should also be clear enough)

Carlos
--

James Kanze

unread,
Oct 31, 2006, 2:20:57 PM10/31/06
to

> [snip]

That's because IEEE 754 is a binary format. There are no
decimal operations, only binary.

Greg's words are entirely correct, at least for quality
implementation: "whether a *floating* *point* *value* is exactly
divisible...". On my machine (and apparently on yours), there
is no floating point value equal to 1.0000000000000001. The
value doesn't exist, so there is obviously no way to test it.

> BTW, if I switch to other implementation using different
> epsilon (for example, intel x87 (epsilon == 2 ^ -63) ), then
> I will get different result.

If you use a different floating point format, you will get
different results, yes. Nothing new here. C++ doesn't impose
any particular floating point representation, and while IEEE is
fairly widespread today, there are still legacy machines
(including IBM mainframes) which use other formats.

The Intel 80x87 implements IEEE 754. A double on a machine
using this processor cannot represent 1.0000000000000001, and
the closest value it can represent is 1.0. So you will get the
same results as you saw.

> Also currently not all compilers support IEEE 754.

It's more a question of the hardware than the compiler.

> So, maybe divided by 1.0 is special, but I am still not sure
> using the methods you and Ganesh purposed I will get the
> reliable exact results or not.

It will give the correct results for all possible double values.
It will not magically convert the double format into an infinit
decimal format. Nor will any other proposed solution.

> > Now it might be helpful were the compiler to warn whenever
> > the specified value of a floating point literal exceeds the
> > precision of its type - but a C++ compiler is not obligated
> > to do so. As long as the specified value lies within (and
> > not beyond) the range of representable values for the type,
> > the compiler is free to round to the closest larger or the
> > closest smaller value (in an implementation-defined manner).

> Yes, the IEEE standard does have the INEXACT trap purposed,
> but most of the compilers just select to ignore it.

I don't think Greg was talking about the execution environment.
All he's saying is that the compilation environment could raise
a warning, e.g. when doing the conversion.

In practice, I don't think it would be acceptable; everyone
would turn the warning off. Because people often use constants
like 1.1, or such, and generally do know that double is not a
real.

> > So without much in the way of help to be expected from the compiler in
> > this kind of situation, it is really up to the programmer to use
> > numeric_limits to check that the precision of a program's floating
> > point calculations is at least able to match the degree of precision
> > expected from them.

> Agreed.

> At least we should add the numeric_limits checking to the above
> two methods.

There's no point in using numeric_limits if you use fmod or
modf. And there's no reason to use anything else.

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Seungbeom Kim

unread,
Oct 31, 2006, 8:43:51 PM10/31/06
to
Alberto Ganesh Barbati wrote:
> However, if d is the result of a floating-point valued expression such as:
>
> double d = 1000.f / 10.f;
>
> then you can't be be sure that the fractional part is *exactly* zero due
> to rounding errors.

I doubt it; aren't integers always exactly represented, as long as
they fit in the range? So 1000.f and 10.f are exact, and I expect
1000.f / 10.f to be also exact.

(Of course, this applies to the IEEE floating point types.)

--
Seungbeom Kim

Seungbeom Kim

unread,
Oct 31, 2006, 8:44:23 PM10/31/06
to
Jiang wrote:
>
> On Oct 31, 12:05 am, Seungbeom Kim <musip...@bawi.org> wrote:
>> Seungbeom Kim wrote:
>>
>>> (int)d suffers from a possible overflow - the integral portion of d
>>> might not be representable in an int. Using floor(d) seems better.
>>> You might also want to consider allowing a small amount of error:
>>> bool is_integer(double d)
>>> {
>>> return fabs(d - floor(d)) < 1e-6; // for example
>>> }My mistake here; this actually depends on the sign of the error.
>> For example, if is_integer(d) will return false for d == 3 - 1e-7 or
>> d == -3 - 1e-7, contrary to my intent.
>>
>> A quick fix is to replace floor() with round() (available in C99).
>>
>
> But what is the rationale for choosing eps as a
> magic number 1e-6?

If you deal only with integers or real numbers up to a few digits below
the decimal point, 1e-6 is sufficiently small to be an error rather than
meaningful. Maybe that's why the default precision for "%f" is 6.

However, it was just an example, as noted; you may have to choose your
own value that fits your application.

> And, for your example, it is strange that a floating
> point number 2.9999999 *contains* a integer 3, well,
> if we use FE_TONEAREST flag.

It would be a bit weird to say that the number 2.9999999 contains an
integer 3; my intent is whether the variable of type double contains a
value that can be considered as an integer, and depending on what you
need it for, 2.9999999 may be considered as a (contaminated) integer.

I don't understand what it means to "use FE_TONEAREST flag".

--
Seungbeom Kim

Jiang

unread,
Nov 1, 2006, 3:13:13 AM11/1/06
to

Seems my last night's follow-up was not posted to moderators
successfully...

Alberto Ganesh Barbati wrote:
> Jiang ha scritto:
> >

[snip]

> >
> > Is it the problem of double value representation? Or, the comprison
> > is not reliable?
> >
> >
>
> The former. As log2(0.0000000000000001) is about -53.15, in order to
> correctly represent 1.0000000000000001 in base-2 floating point you need
> at least 54 bits of mantissa. However, typical implementations of double
> (for example on ix86 machines) only use 53 bits. So when you load
> 1.0000000000000001 into d, you are actually storing 1.
>


Yes, as I said in another post, my machine can not handle such
a small difference.


> However, the comparison is a big point of weakness of the algorithm. If
> you assign to d an integral expression such as in:
>
> double d = 1000;
>
> then you can be reasonably sure that the fractional part is zero.
> However, if d is the result of a floating-point valued expression such as:
>
> double d = 1000.f / 10.f;
>
> then you can't be be sure that the fractional part is *exactly* zero due
> to rounding errors.


I am not sure I get your point here.

The fractional part of your double value d should be represented
exactly, because 100.0 could be interpreted successfully using
binary format.

Did you mean that for

double e = 1000.f / 10000.f

the fractional part is not exact zero? This is true, because
we do not have a binary representation for 1.0 / 10.0 at all.


> You should always check floating point values with
> <, <=, > or >=. Using == and != for floating point is looking for
> trouble. Unfortunately, the naive implementation:
>


I tend to avoid ">=" and "<=" for floating point number comparison.


> // wrong implementation!
> bool is_integer(double d, double epsilon = 0.0000001)
> {
> return fabs(modf(d, 0)) < epsilon;
> // alternatively: fabs(fmod(d, 1.0)) < epsilon
> }
>
> will produce incorrect results, because:
>
> modf(1.0000001, 0) == 0.0000001
> modf(1.0000000, 0) == 0.0000000
> modf(0.9999999, 0) == 0.9999999
>
> a more correct way is:
>
> bool is_integer(double d, double epsilon = 0.0000001)
> {
> double f = modf(d, 0); // or fmod(d, 1.0)


Passing "0" to modf's 2nd parameter will invoke undefined behavior. :-)

// correct the typo
double ipart;
doulbe f = modf(d, &ipart);

Jiang

unread,
Nov 1, 2006, 3:12:36 AM11/1/06
to

Seungbeom Kim wrote:
> Jiang wrote:
> >

[snip]

> >
> > But what is the rationale for choosing eps as a
> > magic number 1e-6?
>
> If you deal only with integers or real numbers up to a few digits below
> the decimal point, 1e-6 is sufficiently small to be an error rather than
> meaningful. Maybe that's why the default precision for "%f" is 6.
>
> However, it was just an example, as noted; you may have to choose your
> own value that fits your application.
>


Thanks, I saw your point from your and others posts.

I asked this question because I was thinking the OP want a
*exact* evaluation in his test function, and the epsilon for
practical numerical computation is not that important.

BTW, it is true 1e-6 is frequently used for representing float type
epsilon, however, if we use double type, maybe the number
should be even smaller ( for example, 1e-9 ).


> > And, for your example, it is strange that a floating
> > point number 2.9999999 *contains* a integer 3, well,
> > if we use FE_TONEAREST flag.
>
> It would be a bit weird to say that the number 2.9999999 contains an
> integer 3; my intent is whether the variable of type double contains a
> value that can be considered as an integer, and depending on what you
> need it for, 2.9999999 may be considered as a (contaminated) integer.
>

Yes, it is not a problem if exact solution is not a requirement.

> I don't understand what it means to "use FE_TONEAREST flag".
>

Oh, nothing special, I just added it to specify the explicit behavior
for C99's round operation, it can be ignored for our current context.


--

Alberto Ganesh Barbati

unread,
Nov 1, 2006, 5:03:39 AM11/1/06
to
Jiang ha scritto:

>> However, if d is the result of a floating-point valued expression such as:
>>
>> double d = 1000.f / 10.f;
>>
>> then you can't be be sure that the fractional part is *exactly* zero due
>> to rounding errors.
>
> I am not sure I get your point here.
>
> The fractional part of your double value d should be represented
> exactly, because 100.0 could be interpreted successfully using
> binary format.
>
> Did you mean that for
>
> double e = 1000.f / 10000.f

No, I meant

double d = 1000.f * 0.1f;

>
> I tend to avoid ">=" and "<=" for floating point number comparison.
>

The are useful for example if you have to check a value that conceivably
might be exactly 0. (This might happen if it has been explicitly
assigned that value).

>>
>> bool is_integer(double d, double epsilon = 0.0000001)
>> {
>> double f = modf(d, 0); // or fmod(d, 1.0)
>
>
> Passing "0" to modf's 2nd parameter will invoke undefined behavior. :-)
>
> // correct the typo
> double ipart;
> doulbe f = modf(d, &ipart);
>

Right. I recalled that retrieving the integer part was optional, but
it's not. Thanks for pointing that out. I probably made confusion with
the other thread on this NG about strtoul...

Ganesh

Seungbeom Kim

unread,
Nov 1, 2006, 7:11:42 AM11/1/06
to
Jiang wrote:
>
> Did you mean that for
>
> double e = 1000.f / 10000.f
>
> the fractional part is not exact zero? This is true, because
> we do not have a binary representation for 1.0 / 10.0 at all.

It shouldn't be zero, anyway. :)
It's true that 1/10 cannot be represented exactly.

>> You should always check floating point values with
>> <, <=, > or >=. Using == and != for floating point is looking for
>> trouble. Unfortunately, the naive implementation:
>
> I tend to avoid ">=" and "<=" for floating point number comparison.

Would you explain why, and what you use instead?

--
Seungbeom Kim

Francis Glassborow

unread,
Nov 1, 2006, 11:45:20 AM11/1/06
to
In article <HuZ1h.24407$Fk1....@twister2.libero.it>, Alberto Ganesh
Barbati <Alberto...@libero.it> writes

>> Did you mean that for
>> double e = 1000.f / 10000.f
>
>No, I meant
>
> double d = 1000.f * 0.1f;
In mathematics those are equivalent computations, for a computer they
are not. Whether they produce the same result depends on the coding used
for floating point values (which does not have to be binary)


--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

Francis Glassborow

unread,
Nov 1, 2006, 11:46:24 AM11/1/06
to
In article <ei9o7a$8mt$1...@news.Stanford.EDU>, Seungbeom Kim
<musi...@bawi.org> writes

>Jiang wrote:
>>
>> Did you mean that for
>>
>> double e = 1000.f / 10000.f
>>
>> the fractional part is not exact zero? This is true, because
>> we do not have a binary representation for 1.0 / 10.0 at all.
>
>It shouldn't be zero, anyway. :)
>It's true that 1/10 cannot be represented exactly.

On a system that represents floats in binary, but there is actually no
requirement to do so and there have been and are systems that use a
decimal representation for floating point values (there are also systems
that use other bases but those fall foul of the exact representation
limit)


--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

DeCaf

unread,
Nov 2, 2006, 6:11:44 AM11/2/06
to
To complete this discussion, it would also be interesting to find out a
good way to figure out not only if the double (or other floating point
type) contains an integer, for which I think we've found a few working
ways, but also to find out if that value will fit in a specific integer
type.

Would the following test suffice for that?

bool is_int(double d)
{

return std::fmod(d, 1.0) == 0.0 &&
f >= (double)std::numeric_limits<int>::min() &&
f <= (double)std::numeric_limits<int>::max();
}

If we for the moment disregard any rounding errors. Obviously the
above would fail if double can not contain the max/min of the integer
type, but that doesn't really seem feasible, does it?


--

Alberto Ganesh Barbati

unread,
Nov 2, 2006, 1:29:14 PM11/2/06
to
DeCaf ha scritto:

> To complete this discussion, it would also be interesting to find out a
> good way to figure out not only if the double (or other floating point
> type) contains an integer, for which I think we've found a few working
> ways, but also to find out if that value will fit in a specific integer
> type.
>
> Would the following test suffice for that?
>
> bool is_int(double d)
> {
>
> return std::fmod(d, 1.0) == 0.0 &&
> f >= (double)std::numeric_limits<int>::min() &&
> f <= (double)std::numeric_limits<int>::max();
> }
>
> If we for the moment disregard any rounding errors. Obviously the
> above would fail if double can not contain the max/min of the integer
> type, but that doesn't really seem feasible, does it?
>

On a typical implementation with 32-bit integers and doubles with 53
bits of mantissa, ints are always represented exactly. However, if your
implementation has 64-bit integers, which can not be represented
exactly, your test may potentially succeed when it should fail or
viceversa. However, in that case the meaning of "a float that contains
an integer" is flawed in the first place (every number greater than 2^53
is represented with a fractional part equal to 0).

Ganesh

PS: I did a sanity check about my preference of using modf over fmod. A
simple benchmark on my machine (ix86-based, Windows, VC++ 7.1) has shown
that fmod is typically 50% slower than modf.

Victor Bazarov

unread,
Nov 2, 2006, 1:39:16 PM11/2/06
to
DeCaf wrote:
> To complete this discussion, it would also be interesting to find out
> a good way to figure out not only if the double (or other floating
> point type) contains an integer, for which I think we've found a few
> working ways, but also to find out if that value will fit in a
> specific integer type.
>
> Would the following test suffice for that?

Seems OK to me, but I'd make it a template.

>
> bool is_int(double d)

template<class T>
bool fits_into(double d)

> {
>
> return std::fmod(d, 1.0) == 0.0 &&
> f >= (double)std::numeric_limits<int>::min() &&

... numeric_limits<T>::min() &&

> f <= (double)std::numeric_limits<int>::max();

... numeric_limits<T>::max();

> }
>
> If we for the moment disregard any rounding errors. Obviously the
> above would fail if double can not contain the max/min of the integer
> type, but that doesn't really seem feasible, does it?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Francis Glassborow

unread,
Nov 2, 2006, 1:41:21 PM11/2/06
to
In article <1162421416.4...@k70g2000cwa.googlegroups.com>,
DeCaf <peter....@gmail.com> writes

>To complete this discussion, it would also be interesting to find out a
>good way to figure out not only if the double (or other floating point
>type) contains an integer, for which I think we've found a few working
>ways, but also to find out if that value will fit in a specific integer
>type.
>
>Would the following test suffice for that?
>
>bool is_int(double d)
>{
>
> return std::fmod(d, 1.0) == 0.0 &&
> f >= (double)std::numeric_limits<int>::min() &&
> f <= (double)std::numeric_limits<int>::max();
>>
>
>If we for the moment disregard any rounding errors. Obviously the
>above would fail if double can not contain the max/min of the integer
>type, but that doesn't really seem feasible, does it?

Perhaps, but I would very much prefer to see the first test replaced
with:
std::floor(f) == std::ceil(f);

and note that C++ overloads floor() and ceil() for the different
floating point types. I think this is one of the few places where
comparisons of floating point values are safe.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

DeCaf

unread,
Nov 2, 2006, 4:19:58 PM11/2/06
to

Alberto Ganesh Barbati skrev:

> bits of mantissa, ints are always represented exactly. However, if your
> implementation has 64-bit integers, which can not be represented
> exactly, your test may potentially succeed when it should fail or
> viceversa. However, in that case the meaning of "a float that contains
> an integer" is flawed in the first place (every number greater than 2^53
> is represented with a fractional part equal to 0).

I guess what I am looking for with my somewhat fuzzy statement "float
contains an integer" is if the value contained in the float can be
safely converted to an integer type without any loss of information.
Of course it should then also be possible to convert it back to the
floating point type and it should still have the same value.

If every number greater than 2^53 in the example above is represented
with a fractional part of 0 that should not pose a problem with
converting it to a 64-bit integer, since neither of them have
fractional parts. However, if the integer can not be accurately
represented in the floating point type, the test should fail. The
question that remains I suppose, is if any, or all of, the tests
mentioned so far (std::fmod, std::modf and std::ceil(x) ==
std::floor(x)) would indicate this correctly?

Seungbeom Kim

unread,
Nov 3, 2006, 4:15:58 AM11/3/06
to
DeCaf wrote:
>
> I guess what I am looking for with my somewhat fuzzy statement "float
> contains an integer" is if the value contained in the float can be
> safely converted to an integer type without any loss of information.
> Of course it should then also be possible to convert it back to the
> floating point type and it should still have the same value.

Then your objective was clearly different from what most other people
thought it was. IIRC many were thinking of whether the value was an
"integer" in an abstract sense (i.e. just whether the fractional part
was zero), not whether the value could fit in a specific integer type
(e.g. int).

> If every number greater than 2^53 in the example above is represented
> with a fractional part of 0 that should not pose a problem with
> converting it to a 64-bit integer, since neither of them have
> fractional parts. However, if the integer can not be accurately
> represented in the floating point type, the test should fail. The
> question that remains I suppose, is if any, or all of, the tests
> mentioned so far (std::fmod, std::modf and std::ceil(x) ==
> std::floor(x)) would indicate this correctly?

None of those methods test whether the value fits in an integer type.
"Integers" that those functions deal with are still represented in the
type double and considered in the domain of type double.

--
Seungbeom Kim

DeCaf

unread,
Nov 3, 2006, 6:18:10 AM11/3/06
to

Seungbeom Kim wrote:
> DeCaf wrote:

> Then your objective was clearly different from what most other people
> thought it was. IIRC many were thinking of whether the value was an
> "integer" in an abstract sense (i.e. just whether the fractional part
> was zero), not whether the value could fit in a specific integer type
> (e.g. int).

Well, that is step one, since if the fractional part is not zero, it
should not be possible to convert the value into an integer and back
with the same value retained, right?

> > If every number greater than 2^53 in the example above is represented
> > with a fractional part of 0 that should not pose a problem with
> > converting it to a 64-bit integer, since neither of them have
> > fractional parts. However, if the integer can not be accurately
> > represented in the floating point type, the test should fail. The
> > question that remains I suppose, is if any, or all of, the tests
> > mentioned so far (std::fmod, std::modf and std::ceil(x) ==
> > std::floor(x)) would indicate this correctly?
>
> None of those methods test whether the value fits in an integer type.
> "Integers" that those functions deal with are still represented in the
> type double and considered in the domain of type double.

What I meant was whether they only return true whether the floating
point value actually represents an integer, i.e. the fractional part is
exactly zero. Testing whether that integer fits within a certain
integer type would have to be done by other means.

In other words, are there integer numbers that cannot be exactly
represented eg. in a double? If so, let's say that for an example 3.0
could not be accurately represented but was instead represented as
2.9999, will the std::fmod, std::modf and the ceil==floor method
indicate that this IS an integer, or would it recognize that the
fractional part is non-zero? (Of course this question is not relevant
if indeed any integer *can* be represented accurately in a double).


--

Maurizio Loreti

unread,
Nov 3, 2006, 6:16:35 AM11/3/06
to
"DeCaf" <peter....@gmail.com> writes:

> I guess what I am looking for with my somewhat fuzzy statement "float
> contains an integer" is if the value contained in the float can be
> safely converted to an integer type without any loss of information.
> Of course it should then also be possible to convert it back to the
> floating point type and it should still have the same value.

So, if *this* is your definition: write a bool function "float
contains an integer" that converts your value to an integer, and then
back to float; and returns 'true' if the float values are bit-by-bit
the same.

--
Maurizio Loreti
http://www.pd.infn.it/~loreti/mlo.html
Dept. of Physics, Univ. of Padova, Italy ROT13:
ybe...@cq.vasa.vg

Francis Glassborow

unread,
Nov 3, 2006, 7:50:28 AM11/3/06
to
In article <rm7iycg...@mlinux.pd.infn.it>, Maurizio Loreti
<m...@foobar.it> writes

>"DeCaf" <peter....@gmail.com> writes:
>
>> I guess what I am looking for with my somewhat fuzzy statement "float
>> contains an integer" is if the value contained in the float can be
>> safely converted to an integer type without any loss of information.
>> Of course it should then also be possible to convert it back to the
>> floating point type and it should still have the same value.
>
>So, if *this* is your definition: write a bool function "float
>contains an integer" that converts your value to an integer, and then
>back to float; and returns 'true' if the float values are bit-by-bit
>the same.


That is a recipe for undefined behaviour. You must use an unsigned
integer type. In addition you will need to keep track of the sign of the
floating point value.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

Francis Glassborow

unread,
Nov 3, 2006, 7:50:01 AM11/3/06
to
In article <1162494612.0...@b28g2000cwb.googlegroups.com>,
DeCaf <peter....@gmail.com> writes

>If every number greater than 2^53 in the example above is represented
>with a fractional part of 0 that should not pose a problem with
>converting it to a 64-bit integer, since neither of them have
>fractional parts.

With the greatest respect, rubbish. The range of values for even a
simple float massively exceeds that for even a 128-bit integer. Any
floating point value with a characteristic greater than 21 is outside
the range of 64-bit integers and greater than 42 is outside the range of
128-bit integers (and I am being a little conservative)

--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

Alberto Ganesh Barbati

unread,
Nov 3, 2006, 12:10:01 PM11/3/06
to
Francis Glassborow ha scritto:

> In article <rm7iycg...@mlinux.pd.infn.it>, Maurizio Loreti
> <m...@foobar.it> writes
>> "DeCaf" <peter....@gmail.com> writes:
>>
>>> I guess what I am looking for with my somewhat fuzzy statement "float
>>> contains an integer" is if the value contained in the float can be
>>> safely converted to an integer type without any loss of information.
>>> Of course it should then also be possible to convert it back to the
>>> floating point type and it should still have the same value.
>>
>> So, if *this* is your definition: write a bool function "float
>> contains an integer" that converts your value to an integer, and then
>> back to float; and returns 'true' if the float values are bit-by-bit
>> the same.
>
> That is a recipe for undefined behaviour. You must use an unsigned
> integer type. In addition you will need to keep track of the sign of the
> floating point value.
>

AFAIK the main flaw of the OP's recipe is that the conversion from float
to integer produces undefined behavior if the truncated float value
can't be represented in the target integer type (that occurs iff the
magnitude of the float is too big). How don't see how using unsigned
integers could help solving this problem. In fact it creates another
problem because you would have to perform an addition check to discard
integer values that are representable in an unsigned int but not in an int.

Ganesh

--

Seungbeom Kim

unread,
Nov 4, 2006, 2:01:09 PM11/4/06
to
DeCaf wrote:

> Seungbeom Kim wrote:
>
>> Then your objective was clearly different from what most other people
>> thought it was. IIRC many were thinking of whether the value was an
>> "integer" in an abstract sense (i.e. just whether the fractional part
>> was zero), not whether the value could fit in a specific integer type
>> (e.g. int).
>
> Well, that is step one, since if the fractional part is not zero, it
> should not be possible to convert the value into an integer and back
> with the same value retained, right?

Right.

> In other words, are there integer numbers that cannot be exactly
> represented eg. in a double?

Of course. Double is not a panacea. :)

All you can say for an IEEE floating-point type is that an integral
value in the range of the type does not get "polluted" with a spurious
fractional part but stored as an integer.

... which is not the case for a non-integral value such as 0.1, which is
indeed in the range of any floating-point type but does get polluted
with smaller fractional values. (The two cases are the same in
principle, but appear to be different because integral values "appear"
to be exact but fractional values such as 0.000110011... do not.)

> If so, let's say that for an example 3.0
> could not be accurately represented but was instead represented as
> 2.9999, will the std::fmod, std::modf and the ceil==floor method
> indicate that this IS an integer, or would it recognize that the
> fractional part is non-zero? (Of course this question is not relevant
> if indeed any integer *can* be represented accurately in a double).

For "sufficiently small" integral values, no problem; 3.0 will never be
represented as 2.9999 or 3.0001. However, large values can suffer from
errors. For example:

// assuming DBL_DIG == 15
double a = 1e16;
double b = 1e16 + 1;
assert(b - a == 1); // fails!

Here, 1e16 + 1 is an integer (in that it doesn't have any fractional
part, not that it fits in an "int") but it cannot be represented exactly
in double, but represented the same as 1e16 instead (on my platform).
It's not that the fractional part is nonzero, but that the precision
gets coarse and the distance between the adjacent representable numbers
becomes greater than 1.

The variable b still contains an integer, so all of the three methods
will tell you that it is an integer indeed (and it is), but they won't
tell you whether the value has suffered from any error (because the
error will also be integral).

If you want to convert to double a value that's already contained in a
variable of an integral type: conversion from a 32-bit integer to an
IEEE double should be no problem because ceil(log10(2^31)) < 15, but
conversion from a 64-bit integer will be a problem.

And of course, double cannot represent any integer that's greater than
DBL_MAX in magnitude. :)

--
Seungbeom Kim

James Kanze

unread,
Nov 5, 2006, 10:01:41 AM11/5/06
to
Francis Glassborow wrote:
> In article <rm7iycg...@mlinux.pd.infn.it>, Maurizio Loreti
> <m...@foobar.it> writes
> >"DeCaf" <peter....@gmail.com> writes:

> >> I guess what I am looking for with my somewhat fuzzy statement "float
> >> contains an integer" is if the value contained in the float can be
> >> safely converted to an integer type without any loss of information.
> >> Of course it should then also be possible to convert it back to the
> >> floating point type and it should still have the same value.

> >So, if *this* is your definition: write a bool function "float
> >contains an integer" that converts your value to an integer, and then
> >back to float; and returns 'true' if the float values are bit-by-bit
> >the same.

> That is a recipe for undefined behaviour. You must use an unsigned
> integer type. In addition you will need to keep track of the sign of the
> floating point value.

Using an unsigned integer type doesn't change anything. Unlike
converting a signed integer to unsigned, converting floating
point to unsigned is NOT defined modulo; if the "truncated
value" doesn't fit, the behavior is undefined.

I think the simplest solution would be something along the lines
of:

bool
converts_exactly_to_int( double d )
{
return trunc( d ) <= std::numeric_limits< int >::max()
&& trunc( d ) >= std::numeric_limits< int >::min()
&& (double)(int)d == d ;
}

--
James Kanze (Gabi Software) email: james...@gmail.com


Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


--

Jiang

unread,
Nov 7, 2006, 3:52:32 AM11/7/06
to
Seungbeom Kim wrote:
> Jiang wrote:
> >
> > Did you mean that for
> >
> > double e = 1000.f / 10000.f
> >
> > the fractional part is not exact zero? This is true, because
> > we do not have a binary representation for 1.0 / 10.0 at all.
>
> It shouldn't be zero, anyway. :)
> It's true that 1/10 cannot be represented exactly.
>


Oops!

You are absolutely correct and seems I tried to show my
point using an stupid example.

But I hope you get my point here. :-)


> >> You should always check floating point values with
> >> <, <=, > or >=. Using == and != for floating point is looking for
> >> trouble. Unfortunately, the naive implementation:
> >
> > I tend to avoid ">=" and "<=" for floating point number comparison.
>
> Would you explain why,


Well, the operator ">=" and "<=" can not handle some
special cases, which we must handle for floating point number.

For example, usually we use relative error for equality evaluation,
however, the following code shows that:

$ cat comp.cpp

#include <assert.h>

int main()
{
// suppose we get a and b using complex algorithms
double a = 0.;
double b = 0.;
assert( a <= (a-b)/b );
}

$ ./comp
assertion "a <= (a-b)/b" failed: file "comp.cpp", line 8
Hangup


The above assertion fails because 0.0/0.0 yields NaN, and most
implementations will simply ignore the exception and the above
evolution will never be true, even we know a and b are both exact 0.0 .

> and what you use instead?
>

It depends. It is possible to remove the "exactly equal" conditions
from my algorithms, or, it is even possible to use integer for
such kind of evaluations.

Similar idea can be found at:


http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm


--

Seungbeom Kim

unread,
Nov 8, 2006, 5:32:24 AM11/8/06
to
Jiang wrote:
> Seungbeom Kim wrote:
>> Jiang wrote:
>>> I tend to avoid ">=" and "<=" for floating point number comparison.
>> Would you explain why,
>
> Well, the operator ">=" and "<=" can not handle some
> special cases, which we must handle for floating point number.
>
> For example, usually we use relative error for equality evaluation,
> however, the following code shows that:
>
> $ cat comp.cpp
>
> #include <assert.h>
>
> int main()
> {
> // suppose we get a and b using complex algorithms
> double a = 0.;
> double b = 0.;
> assert( a <= (a-b)/b );
> }
>
> $ ./comp
> assertion "a <= (a-b)/b" failed: file "comp.cpp", line 8
> Hangup
>
>
> The above assertion fails because 0.0/0.0 yields NaN, and most
> implementations will simply ignore the exception and the above
> evolution will never be true, even we know a and b are both exact 0.0 .

Shouldn't you have avoided division by zero in the first place?
((a-b)/a<e can be rewritten as a-b<e*a to avoid division by zero.)
I don't think it's the problem of >= and <=. It is reasonable to use the
notion of relative error for equality tests, but why for inequalities?
How do you define "a is relatively less than (or equal to) b", and how
does it differ from just saying "a is less than (or equal to) b"?

> It depends. It is possible to remove the "exactly equal" conditions
> from my algorithms, or, it is even possible to use integer for
> such kind of evaluations.
>
> Similar idea can be found at:
>
>
> http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

It's a nice idea described there, but it only tells about replacing ==
(and !=, consequently) with a better method, not >= or <=.

--
Seungbeom Kim

0 new messages