Say if I have an NSNumber, which is something between 0 and 1, and it can be represented using X/Y, how do I calculate the X and Y in this case? I don’t want to compare:
if (number.doubleValue == 0.125)
{
X = 1;
Y = 8;
}
so I get 1/8 for 0.125
That’s relatively straightforward. For example,
0.375is equivalent to0.375/1.First step is to multiply numerator and denominator until the numerator is an integral value (a), giving you
375/1000.Then find the greatest common divisor and divide both numerator and denominator by that.
A (recursive) function for GCD is:
If you call that with
375and1000, it will spit out125so that, when you divide the numerator and denominator by that, you get3/8.(a) As pointed out in the comments, there may be problems with numbers that have more precision bits than your integer types (such as IEEE754 doubles with 32-bit integers). You can solve this by choosing integers with a larger range (longs, or a bignum library like MPIR) or choosing a “close-enough” strategy (consider it an integer when the fractional part is relatively insignificant compared to the integral part).
Another issue is the fact that some numbers don’t even exist in IEEE754, such as the infamous
0.1and0.3.Unless a number can be represented as the sum of
2-nvalues wherenis limited by the available precision (such as0.375being1/4 + 1/8), the best you can hope for is an approximation.Example, consider the single-precision (you’ll see why below, I’m too lazy to do the whole 64 bits)
1/3. As a single precision value, this is stored as:In this example, the sign is
0hence it’s a positive number.The exponent bits give 125 which, when you subtract the 127 bias, gives you -2. Hence the multiplier will be
2-2, or0.25.The mantissa bits are a little trickier. They form the sum of an explicit
1along with all the2-nvalues for the1bits, wherenis 1 through 23 (left to right. So the mantissa is calculated thus:When you multiply that by
0.25(see exponent earlier), you get:Now that’s why they say you only get about 7 decimal digits of precision (15 for IEEE754 double precision).
Were you to pass that actual number through my algorithm above, you would not get
1/3, you would instead get:But that’s not a problem with the algorithm per se, more a limitation of the numbers you can represent.
Thaks to Wolfram Alpha for helping out with the calculations. If you ever need to do any math that stresses out your calculator, that’s one of the best tools for the job.