Your immediate problem has to do with the imprecision of floating point numbers, something that is generally well documented on the net, including various methods useful in fixing that problem.
However, I'm not actually going to bother referring you to them because the use of floating point is totally unnecessary here. There's a much more efficient way of doing this that involves only integers.
Rather than going through numbers in your range looking for powers of three using floating point operations, you would be better off going through powers of three (using just integer multiplication) looking for numbers in your range.
In pseudo-code, that would go something like:
powerOfThree = 1
while powerOfThree <= endRange:
if powerOfThree >= startRange:
print powerOfThree
powerOfThree = powerOfThree * 3
You could even make it more efficient by selecting a more suitable starting value for powerOfThree
but, since there are only 40-odd powers of three in a 64 bit number, that's probably a waste of time.
When converting from pseudo-code to the more concrete C, you unfortunately come across the limitations of the datatypes in that language, specifically the fact that multiplication may result in overflow.
There are various ways you can avoid this this such as detecting that it's about to happen and exiting the loop early.
Given below is the function that you need, one which handles this issue, along with some test code which can be used for validating it.
#include <stdio.h>
#include <limits.h>
// I hate typing :-)
typedef unsigned long ULONG;
typedef unsigned int UINT;
static UINT countPowersOfThreeBetween (ULONG low, ULONG high) {
// Catch invalid params, just exit with zero.
if (low > high) return 0;
// Go through all powers of three.
ULONG powerOfThree = 1;
UINT count = 0;
do {
// If within your range, count it.
if ((powerOfThree >= low) && (powerOfThree <= high)) {
count++;
// printf ("DEBUG: got %lu\n", powerOfThree);
}
// Early exit if about to overflow.
if (ULONG_MAX / powerOfThree < 3) break;
// Advance to next power and continue if within range.
powerOfThree *= 3;
} while (powerOfThree <= high);
// Notify caller of count.
return count;
}
// Test function to make test suite easier.
static void testRange (ULONG low, ULONG high) {
UINT count = countPowersOfThreeBetween (low, high);
printf ("In range %lu..%lu, found %u occurrences\n", low, high, count);
}
// Test suite, add whatever you need.
int main (void) {
testRange (1000, 10);
testRange (0, 0);
testRange (9, 9);
testRange (3, 1000);
testRange (0, ULONG_MAX);
testRange (ULONG_MAX, ULONG_MAX);
return 0;
}
As you will see from the output, this gives the correct counts for various ranges:
In range 1000..10, found 0 occurrences
In range 0..0, found 0 occurrences
In range 9..9, found 1 occurrences
In range 3..1000, found 6 occurrences
In range 0..18446744073709551615, found 41 occurrences
In range 18446744073709551615..18446744073709551615, found 0 occurrences
And, if you uncomment the printf
line in countPowersOfThreeBetween()
, you'll also see the actual values detected.