float can represent a wider range of numbers than int , but it cannot represent all the values in this range - as you approach the edge of the range (i.e. as the values increase), the gap between the values presented becomes wider.
For example, if you cannot represent values between 0.123 and 0.124, then you also cannot represent values between 123.0 and 124.0, or 1230.0 and 1240.0, or 12300.0 and 12400.0, etc. (of course, the IEEE-754 with one precision float gives you a bit more accuracy).
Having said that the float should be able to represent all integer values up to 2 24 so I'll bet that the problem is calling printf - the float parameters "advance" to double , so there is a change in representation, and this may take into account the lost accuracy.
Try changing the return type of factorial to double and see if that helps.
<gratis rant>
Every time I see a recursive factorial function, I want to scream. Recursion in this particular case does not improve code clarity or performance compared to an iterative solution:
double fac( int x ) { double result = 1.0; while ( x ) { result *= x--; } return result; }
and actually can lead to worse performance due to the overhead of so many function calls.
Yes, the definition of factorial is recursive, but the implementation of a factorial function is optional. The same goes for Fibonacci sequences. There is even a closed-loop solution for Fibonacci numbers
F n = ((1 + √5) n - (1 - √5) n ) / (2 n * √5)
which does not require any cycle in the first place.
Recursion is great for algorithms that split their data into a relatively small number of subsets of the same size (Quicksort, tree traversal, etc.). Something like this, where the partition is N-1 subsets of 1 element? Not so much.
</ grantuit rant>