Strange behavior with casting primitive types

G

Gaijinco

Why does this not work properly?

It's a way to know if how many decimal numbers have a double.

#include <iostream>
using namespace std;

int countDecimals(double d) {
int x = (int)d;
int decimals = 0;
while((x/d) != 1.0) {
d *= 10.0;
x = (int)d;
++decimals;
//cout << x/d << endl; getchar();
}
return decimals;
}

int main() {
cout << countDecimals(3.1415);
return 0;
}

In my computer the answer is OK with 3 or less decimal numbers, but
wrong for everything else!

Thanks!
 
A

Alf P. Steinbach

* Gaijinco:
Why does this not work properly?

It's a way to know if how many decimal numbers have a double.

With most C++ implementations a 'double' value is not represented as a decimal
number, so it simply doesn't have decimals.

#include <iostream>
using namespace std;

int countDecimals(double d) {
int x = (int)d;
int decimals = 0;
while((x/d) != 1.0) {
d *= 10.0;
x = (int)d;
++decimals;
//cout << x/d << endl; getchar();
}
return decimals;
}

int main() {
cout << countDecimals(3.1415);

The decimal specification '3.1415' means the double value that is closest to
decimal 3.1415.

return 0;
}

In my computer the answer is OK with 3 or less decimal numbers, but
wrong for everything else!

It's more or less a coincidence that it seems to work the way you thought it
should work, since with a typical C++ implementation you don't have decimal
digits in there.


Cheers & hth.,

- Alf
 
M

Marcel Müller

Gaijinco said:
Why does this not work properly?

It's a way to know if how many decimal numbers have a double.

#include <iostream>
using namespace std;

int countDecimals(double d) {
int x = (int)d;
int decimals = 0;
while((x/d) != 1.0) {

In general the above condition is always true since an approximate
number will never be exactly equal to something special, because it is
an /approximate/ number. You can be lucky that int has more significant
bits than double on your platform. Otherwise you might get a floating
point exception, because the loop never terminates.

Do never equality compare approximate numbers to something else but zero!

Of course, on most platforms integral numbers can be represented exactly
as approximate numbers as long as they are not too large. But one should
not rely on that. In case you can guarantee that, you also could have
choosen an integral data type.

d *= 10.0;
x = (int)d;
++decimals;
//cout << x/d << endl; getchar();
}
return decimals;
}

int main() {
cout << countDecimals(3.1415);
return 0;
}

In my computer the answer is OK with 3 or less decimal numbers, but
wrong for everything else!

Most likely other numbers like 0,3125 are exact too. The reason is
simply that their reduced rational representation has nothing but the
prime factor two in the denominator.


Marcel
 
J

James Kanze

In general the above condition is always true since an
approximate number will never be exactly equal to something
special, because it is an /approximate/ number.

Where do you see any approximate numbers in this code? 1.0 is
exactly representable in every floating point format I know of.

Alf explained the problem correctly, IMHO. I'm not sure what he
really means by "decimal numbers having a double", but since he
doesn't have any decimal numbers in his program, it's really
irrelevant.
You can be lucky that int has more significant bits than
double on your platform. Otherwise you might get a floating
point exception, because the loop never terminates.

Or that he simply didn't try any integer values that couldn't be
represented exactly in a double.
Do never equality compare approximate numbers to something
else but zero!

Don't do any comparisons until you know what you're doing. You
can get in trouble just as quickly with comparisons for
inequality.
Of course, on most platforms integral numbers can be
represented exactly as approximate numbers as long as they are
not too large. But one should not rely on that. In case you
can guarantee that, you also could have choosen an integral
data type.

It depends. On a lot of platforms, the largest integral type
has (or had) 32 bits. An IEEE double can represent all of the
integers up to 2^52 exactly, however, and I've seen it used
simply for the greater range.
 
J

Juha Nieminen

James said:
Where do you see any approximate numbers in this code? 1.0 is
exactly representable in every floating point format I know of.

'd' can be (and often is) an approximation because there's no 1-to-1
mapping between base-10 floating point values (which is what you write
in your C++ source code) and base-2 floating point values, which is what
most systems use internally. Thus when you give a value of the former
type to that function, the compiler will convert it (at compile time)
internally to a value of the latter type, and these two values may not
be equal, hence 'd' may be just an approximation of the original value
in the source code.

Hence x/d and d*10.0 will also be approximations.
 
J

James Kanze

'd' can be (and often is) an approximation because there's no
1-to-1 mapping between base-10 floating point values (which is
what you write in your C++ source code) and base-2 floating
point values, which is what most systems use internally.

Any actual value is exact in itself, but can be an approximation
of some other value outside the system. (In physical systems,
this is always the case, independantly of the representation;
all measurements are inprecise to a certain degree.)

I'm not too sure what the original poster is trying to do. He
said something about whether a "decimal" has a double, which
sounds to me whether, given a decimal x, the value 2*x exists.
Which, of course, doesn't make sense. But as Alf said, using
floating point to evaluate "decimal" characteristics just isn't
going to work---comparison for equality or not. Floating point
doesn't have the characteristics of a decimal, and is not a good
abstraction for the set of "decimal" numbers (whatever that
means---I've always understood decimal as refering to a
representation, and not a set of numbers).
Thus when you give a value of the former type to that
function, the compiler will convert it (at compile time)
internally to a value of the latter type, and these two values
may not be equal, hence 'd' may be just an approximation of
the original value in the source code.

But what is the original value. In the funtion above, the
original value *is* d.
Hence x/d and d*10.0 will also be approximations.

Approximations of what? Saying that something is an
approximation supposes that there is an exact value which is
being approximated. In the function, the only "exact values" I
can see are 1.0 and 10.0, both of which are exactly
representable in all of the floating point formats I know.

Of course, the original poster doubtlessly had something in
mind, and d (and the other calculated values) are likely just
approximations of that something. But until he tells us what,
we can only guess.

(It just occurs to me that what he's asking might be simply
whether a given decimal has an exact representation as a double.
In which case, the solution is to convert it, and see if you
need to round the final results. In other words, you have to
work with the original decimal format.)
 

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,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top