Gaijinco wrote On 09/26/05 16:07,:
Sooner or later everytime I found recreational programming challenges I
stumble with how I test if a number is has decimal places differnt than
0?
For example if I want to know if a number is a square number (i.e. a
number which square root is a positive number as 4, 9, 16 have) I do
something like:
int square = sqrt(number);
if((int)square==square)
// number is a perfect square
.... and the test is a tautology.
else
// number is not a perfect square
Is there a function or a language-specific-way to do this?
The code you've shown will (if it doesn't invoke
undefined behavior) declare that every number is a
perfect square: 1, 2, 3.14, and even -42.
To test whether a floating-point number is an
integer with no fractional part, you could try
if ((int)fpn == fpn) ...
This runs into trouble when the magnitude of fpn
is large, so large that its value is outside the range
of numbers representable as `int'.
As an improvement you might try
if (fmod(fpn, 1.0) == 0.0) ...
This is still vulnerable to the "graininess" of
floating-point numbers, which are not mathematical real
numbers with infinite precision.
You cannot usually expect sqrt(fpn) to be the exact square
root of fpn. sqrt(fpn) will be very close to the exact root,
but will (in general) be just a little bit different from the
true value. There could be several different fpn values for
which sqrt(fpn) would deliver exactly the same slightly wrong
answer: both sqrt(4.0) and sqrt(4.0 + tiny_number) might
produce 2.0 as an answer. If you decide that a number is a
perfect square if its computed square root turns out to be an
integer, you will erroneously conclude that 4.0+tiny_number is
a perfect square.
A possibly more thorough test might compute the square
root, test whether it's an integer, and then test whether
its square equals the original number:
double root = sqrt(number);
if (fmod(root, 1.0) == 0.0 && root * root == number)
.... but even this may have some problems. I am always uneasy
when comparing floating-point quantities for exact equality,
mostly because fpn's are usually regarded as approximations
to begin with. You usually need an "approximately equal"
test of some kind, and such a test isn't well suited to the
purely yet/no nature of perfect squaredom.
For "number-theoretic" calculations you'll usually be much
better off using integers of some flavor. If the numbers grow
large you may need to resort to a "bignum" package; several
are available.