470,631 Members | 1,994 Online

# Testing a float for equivalence to a double.

Hi,

I have some software that does the following (in an attempt to determine
whether the double x, can be represented just as accurately by a float):

void test_it(double x) {
float y = x;
if(x == y) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}

Is this an acceptable way of determining whether the double can be
represented precisely by a float ? Is there some other (perhaps
preferable) way of doing it ?

One problem is that, with the above function, Microsoft compilers tell
you that x==y, no matter what the value of x. That strikes me as being
quite bizarre.

I'm wondering whether, to make the code portable, I should trick MS
compilers into doing what I think is right (which can be done fairly
simply) - or whether I should be concentrating on applying some other
method.

Thing is that I don't want to stuff around with getting that code to
work properly with MS compilers if the whole concept of that code is of
dubious merit to begin with.

Cheers,
Rob

--
To reply by email u have to take out the u in kalinaubears.

Nov 14 '05 #1
9 2214 On Wed, 16 Feb 2005 05:41:29 +0000, Sisyphus wrote:
Hi,

I have some software that does the following (in an attempt to determine
whether the double x, can be represented just as accurately by a float):

void test_it(double x) {
float y = x;
if(x == y) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}

Is this an acceptable way of determining whether the double can be
represented precisely by a float ?
It is as far as standard C is concerned as long as fabs(x) <= FLOAT_MAX.
In the general case you should test for that as well.
Is there some other (perhaps preferable) way of doing it ?

One problem is that, with the above function, Microsoft compilers tell
you that x==y, no matter what the value of x. That strikes me as being
quite bizarre.
Compilers on some platforms, especially x86 ones often choose not to
follow the standard rules exactly because doing so entails a big
performance hit. They prefer to keep values in registers where possible so
they are held at higher precision than they should be.
I'm wondering whether, to make the code portable, I should trick MS
compilers into doing what I think is right (which can be done fairly
simply) - or whether I should be concentrating on applying some other
method.
This is a reasonable approach, and it isn't obvious what else you could
do without examining the representation which won't be portable. Because
we're in a situation where compilers are not following the standard there
is no competely portable method to do this. However making y volatile will
result in the correct behaviour on many compilers.
Thing is that I don't want to stuff around with getting that code to
work properly with MS compilers if the whole concept of that code is of
dubious merit to begin with.

The approach is sensible, it is just a case of making the compiler do the
right thing.

Lawrence
Nov 14 '05 #2

"Sisyphus" <ka**********@iinet.net.au> wrote in message
Hi,

I have some software that does the following (in an attempt to determine
whether the double x, can be represented just as accurately by a float):

void test_it(double x) {
float y = x;
if(x == y) { .... One problem is that, with the above function, Microsoft compilers tell you
that x==y, no matter what the value of x. That strikes me as being quite
bizarre.

Perhaps both are compared as float values, so x is demoted to float and so
will always be the same as y? Or perhaps the parameter x is derived from a
float value elsewhere.

Bart
Nov 14 '05 #3

"Lawrence Kirby" <lk****@netactive.co.uk> wrote in message
news:pa****************************@netactive.co.u k...
On Wed, 16 Feb 2005 05:41:29 +0000, Sisyphus wrote:
Hi,

I have some software that does the following (in an attempt to determine
whether the double x, can be represented just as accurately by a float):

void test_it(double x) {
float y = x;
if(x == y) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}

Is this an acceptable way of determining whether the double can be
represented precisely by a float ?
It is as far as standard C is concerned as long as fabs(x) <= FLOAT_MAX.
In the general case you should test for that as well.

Which cases would be affected by such an additional test? Does testing
representations of Infinity invoke UB? If so, does this fix it?
One problem is that, with the above function, Microsoft compilers tell
you that x==y, no matter what the value of x. That strikes me as being
quite bizarre.

Compilers on some platforms, especially x86 ones often choose not to
follow the standard rules exactly because doing so entails a big
performance hit. They prefer to keep values in registers where possible so
they are held at higher precision than they should be.
I'm wondering whether, to make the code portable, I should trick MS
compilers into doing what I think is right (which can be done fairly
simply) - or whether I should be concentrating on applying some other
method.

Do you consider setting SSE2 code generation as a "trick?" The approach is sensible, it is just a case of making the compiler do the
right thing.

Lawrence

Nov 14 '05 #4
Lawrence Kirby wrote:

This is a reasonable approach, and it isn't obvious what else you could
do without examining the representation which won't be portable. Because
we're in a situation where compilers are not following the standard there
is no competely portable method to do this. However making y volatile will
result in the correct behaviour on many compilers.

Didn't know about "volatile" - so I've just tried it out, but it doesn't
seem to be the answer in this case.

My solution (so far) is to write a separate function for MS compilers:

#ifdef _MSC_VER // identifies Microsoft compilers
void test_it(double x) {
float foo = x;
float y = foo;
if(x == y) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}
#else // use the original

But that worked only if optimizations were not turned on - in which case
the only solution I could find was to turn 'em off:

#ifdef _MSC_VER
#pragma optimize("", off)
void test_it(double x) {
float foo = x;
float y = foo;
if(x == y) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}
#pragma optimize("", on)
#else

But even that wouldn't work if -O1 optimization (minimize space) were
used - in which case an additional 'foo +=0;' was needed. So, a solution
which I *think* covers all cases with MS compilers is to have:

#ifdef _MSC_VER
#pragma optimize("", off)
void test_it(double x) {
float foo = x;
float y = foo;
foo += 0;
if(x == y) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}
#pragma optimize("", on)
#else

I don't think I've added much overhead to the original (though I haven't
tested) but is there something I could try that is not quite so comical ?

Getting back to "volatile", I found that simply making y volatile did
not achieve the desired result - so I did:

volatile float foo = x;
volatile float y = foo;
if(x == y) { ...

But that still didn't do the right thing, so I added 'foo += 0;' as
before, but that produced something that Microsoft calls an "INTERNAL
COMPILER ERROR".

At that point I gave up on that approach :-)

Cheers,
Rob

--
To reply by email u have to take out the u in kalinaubears.

Nov 14 '05 #5
Sisyphus wrote:
Lawrence Kirby wrote:

This is a reasonable approach, and it isn't obvious what else you could
do without examining the representation which won't be portable. Because
we're in a situation where compilers are not following the standard there
is no competely portable method to do this. However making y volatile
will
result in the correct behaviour on many compilers.

Didn't know about "volatile" - so I've just tried it out, but it doesn't
seem to be the answer in this case.

My solution (so far) is to write a separate function for MS compilers:

#ifdef _MSC_VER // identifies Microsoft compilers
void test_it(double x) {
float foo = x;
float y = foo;
if(x == y) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}
#else // use the original

But that worked only if optimizations were not turned on - in which case
the only solution I could find was to turn 'em off:

#ifdef _MSC_VER
#pragma optimize("", off)
void test_it(double x) {
float foo = x;
float y = foo;
if(x == y) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}
#pragma optimize("", on)
#else

But even that wouldn't work if -O1 optimization (minimize space) were
used - in which case an additional 'foo +=0;' was needed. So, a solution
which I *think* covers all cases with MS compilers is to have:

#ifdef _MSC_VER
#pragma optimize("", off)
void test_it(double x) {
float foo = x;
float y = foo;
foo += 0;
if(x == y) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}
#pragma optimize("", on)
#else

I don't think I've added much overhead to the original (though I haven't
tested) but is there something I could try that is not quite so comical ?

Getting back to "volatile", I found that simply making y volatile did
not achieve the desired result - so I did:

volatile float foo = x;
volatile float y = foo;
if(x == y) { ...

But that still didn't do the right thing, so I added 'foo += 0;' as
before, but that produced something that Microsoft calls an "INTERNAL
COMPILER ERROR".

At that point I gave up on that approach :-)

I usually use volatile indirectly:

void test_it(double x) {
float y = x;
if(*((volatile double *)&x) == *((volatile float *)&y)) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}

Maybe this works for you, too. However, do not forget to check
against the maximum float value...
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 14 '05 #6
Michael Mair wrote:

I usually use volatile indirectly:

void test_it(double x) {
float y = x;
if(*((volatile double *)&x) == *((volatile float *)&y)) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}
Thanks for the tip on usage, Michael - though it still doesn't coerce
the MS compiler into behaving as desired :-)

Maybe this works for you, too. However, do not forget to check
against the maximum float value...

Sorry - I should have mentioned that this function won't get called if
|x| is greater than the maximum float value. (ie such a condition will
be detected and dealt with before the function is called.)

Cheers,
Rob

--
To reply by email u have to take out the u in kalinaubears.

Nov 14 '05 #7
On Wed, 16 Feb 2005 14:11:14 +0000, Tim Prince wrote:

....
It is as far as standard C is concerned as long as fabs(x) <= FLOAT_MAX.
In the general case you should test for that as well.

Which cases would be affected by such an additional test? Does testing
representations of Infinity invoke UB? If so, does this fix it?

If you convert a value to float which is not within the range of
representable values of float you get undefined behaviour. Infinities are
not involved here.

Lawrence

Nov 14 '05 #8
Sisyphus wrote:
Michael Mair wrote:

I usually use volatile indirectly:

void test_it(double x) {
float y = x;
if(*((volatile double *)&x) == *((volatile float *)&y)) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}
Thanks for the tip on usage, Michael - though it still doesn't coerce

the MS compiler into behaving as desired :-)

Cheers,
Rob

void test_it(double x) {
union{ float foo; float bar; } volatile schizo;
schizo.foo = x;
if(x == schizo.bar) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}

I haven't tested it though.

Mark

Nov 14 '05 #9
Mark Piffer wrote:

void test_it(double x) {
union{ float foo; float bar; } volatile schizo;
schizo.foo = x;
if(x == schizo.bar) {
printf("x can be represented precisely by a float\n");
}
else {
printf("x can't be represented precisely by a float\n");
}
}

Not quite (nice try :-)

It works with optimization -O1, but fails with both -O2 and with no
optimizations.

Cheers,
Rob

--
To reply by email u have to take out the u in kalinaubears.

Nov 14 '05 #10

### This discussion thread is closed

Replies have been disabled for this discussion.