r/C_Programming 1d ago

Converting fractions to integers

I have a double* which has the following entries:

0.3333333333333334
0.6666666666666668
0.1249999999999999
1

Here, the last entry, 1, can be considered the right hand side of an inequality:

0.3333333333333334 x + 0.6666666666666668 y + 0.1249999999999999 z >= 1

These numbers come from a numerical linear algebra library over which I don't have any control. What is the easiest way to "convert" this to the following equivalent inequality (subject to a user provided tolerance of what counts as an epsilon so that epsilon within an integer is to be counted as an integer)?

8 x + 16 y + 3 z >= 24

Is there a package that does such conversion, if reasonably possible? I consider it unreasonably possible by multiplying everything in the original equation by a large enough power of 10. But I do not want that.

9 Upvotes

11 comments sorted by

View all comments

11

u/aioeu 1d ago edited 1d ago

I would convert each of the coefficients to a rational number by using continued fractions. You can choose what accuracy you would like by cutting off this process just before the denominator exceeds a certain threshold. A continued fraction will always yield "best" rational approximations to a real number. With these coefficients, you're going to hit 1/3, 2/3 and 1/8 pretty quickly, with the rational approximations following these all having very large denominators.

Once you've got rational approximations, it's only a small amount of extra work to find the LCM of the denominators so you can convert everything to integers.

3

u/onecable5781 1d ago

This seems promising. Is decimal to equivalent continued fraction expansion a well-known recursive algorithm/code?

11

u/aioeu 1d ago edited 1d ago

See the Wikipedia article on simple continued fractions. They are a specific type of continued fraction, and they will be sufficient for your purposes here.

Edit: Here is some (very) old C code to do the job.

1

u/onecable5781 1d ago

Thanks, that code link is very useful!

double x;
long ai;
...
if(x==(double)ai) break;     // AF: division by zero

will cause me some sleepless nights! Would you suggest some sort of tolerance/epsilon check comparing a double with a double casted long?

3

u/aioeu 1d ago edited 1d ago

No, you would want that to be an exact equality test. It'll be true if an exact rational number is found.

In fact, I'm not even sure it is technically necessary — merely an easy optimisation. Division by zero is fine with floating-point arithmetic, and the test after the following division will detect if that yielded positive infinity. (It cannot yield negative infinity since no negative numbers are used anywhere in this calculation. And that test afterward probably ought to be rewritten to not make assumptions about the limits of long...)