How to compute โ๐ฅรท๐โ for a variable integer ๐ฅ and a fixed-point rational number ๐โฅ1 precisely? The input ๐ฅ โ [0, INT_MAX] is stored in a variable of type int
, ๐ โ [1, INT_MAX] is given as a decimal literal with a decimal separator in the form ๐๐๐๐๐.๐๐ (you may alternatively represent it as a fraction, say, ๐๐๐๐๐๐๐/100, if this helps, or as a product of prime powers divided by another product of prime powers), and the output should be a value of type int
. Here, รท is mathematical division. Our running example is โ๐ฅรท65781.76โ; within this example, you can assume that int
is at least 3 bytes wide (as otherwise the result would be trivially 0). How to do this in C properly?
Clearly, (int)(๐ฅ/65781.76f)
would involve floating-point arithmetic (and, according to http://www.h-schmidt.net/FloatConverter/IEEE754.html, 65781.76, as most constants, is not precisely representable at least on my machine), whereas 100*๐ฅ/6578176L
and 25*๐ฅ/1644544L
risk an overflow too much. In any case, to my knowledge, adding the suffix L or LL (as in, e.g., 25LL*๐ฅ/1644544L
) is pointless because the types long long
, long
, and int
are not guaranteed to be of different widths. Any other options? I'm interested in solutions involving integer arithmetic only and (most importantly) a proper explanation.
Ideally, we'd like to have a precise and portable solution; if possible, let's stick to C89/C90 without external libraries.
For the specific number in the question, we want โ๐ฅ/65781.76โ = โ๐ฅโข25/(2048โข803)โ = โ๐ฅโข(16+8+1)/2048 / 803โ = โ(๐ฅ/128 + ๐ฅ/256 + ๐ฅ/2048) / 803โ.
Next, we separate the integer and fraction portions of ๐ฅ/128, ๐ฅ/256, and ๐ฅ/2048: โ(โ๐ฅ/128โ + ๐ฅ%128/128 + โ๐ฅ/256โ + ๐ฅ%256/256 + โ๐ฅ/2048โ + x%2048/2048) / 803โ.
Then we group the fractions, using โ%โ to indicate the remainder operation: โ(โ๐ฅ/128โ + โ๐ฅ/256โ + โ๐ฅ/2048โ + ๐ฅ%128/128 + ๐ฅ%256/256 + x%2048/2048) / 803โ.
And consolidate them into one term: โ(โ๐ฅ/128โ + โ๐ฅ/256โ + โ๐ฅ/2048โ + (๐ฅ%128โข16 + ๐ฅ%256โข8 + x%2048)/2048) / 803โ.
Now the only fraction in the sum is in (๐ฅ%128โข16 + ๐ฅ%256โข8 + x%2048)/2048, so we may discard it, taking its integer portion: โ(โ๐ฅ/128โ + โ๐ฅ/256โ + โ๐ฅ/2048โ + โ(๐ฅ%128โข16 + ๐ฅ%256โข8 + x%2048)/2048โ) / 803โ.
So all parts may be calculated with integer arithmetic: (x/128 + x/256 + x/2048 + (x % 128 * 16 + x % 256 * 8 + x % 2048)/2048) / 803
.
Observe that all multiplications, remainders, and divisions except the division by 803 may be computed with bit shifts and masks.
The above relies on the fact that the quotient in question had a power of two in its factorization. In general, given p and q with pโข(qโ1) โค INT_MAX
, we can compute โxโขp/qโ with x/q*p + x%q*p/q
, because โxโขp/qโ = โx/qโขpโ = โ(โx/qโ+x/qโโx/qโ)โขpโ = โโx/qโโขp + (x/qโโx/qโ)โขpโ = โโx/qโโขp + (x%q/qโ)โขpโ = โx/qโโขp + โx%q/qโขpโ = โx/qโโขp + โx%qโขp/qโ.
Thus, for the number in question, we seek โxโข25/1,644,544โ, so we can use x / 1644544 * 25 + x % 1644544 * 25 / 1644544
.
This uses two divisions, one to compute the quotient and remainder of x when divided by q and then a second division by q.