I'm unwilling to guarantee an accurate result via floating point cast unless the mantissa has enough bits to exactly represent all the integral values. For instance, tonsider y=9223372036854775807 and x = (y div 10) - 1 = 922337203685477579. where "div" is integer division. x/y is 0.09999999999999999981568563067746..., but using doubles gets you >= 0.1. This is a result of doubles having only 52 digits of precision in the significand (while y needs 61 bits and x about 58)
You may be able to use 80bit or 128bit FP precision, in which case you'd get the right answer because the mantissa would be >=64bit (ULL are 64bit, right?) and so you'd losslessly represent the numbers.
I'd start with an approximation (either using integer or FP arithmetic) then trial multiplication to see if the answer should be 1 less or more. The key insight is that you can still compare two possibly overflowed ints as long as you know that the difference between the two quantities is less than half the max unsigned int. This sort of comparison technique is necessary when e.g. TCP sequence numbers overflow.
In case you want to use only integer arithmetic, the below function "fdd(x,y)" works. I've included a main() to show some results:
#include <iostream>
using namespace std;
typedef unsigned char ull; // change char to any integral type e.g. long long
const ull maxull=(ull)-1;
const ull halfull = maxull/2;
typedef unsigned long long asint;
// x = X mod (maxull+1), y= Y mod (maxull+1). we only know x and y
// if we assume |X-Y|<halfull, then we return X<Y:
inline bool less_mod_near(ull x, ull y) {
return (x<=halfull == y<=halfull) ? x<y : y>x;
}
// assuming x<y, return first decimal digit of 10x/y (return is in [0..9])
inline int fdd(ull x, ull y) {
// assert(x<y);
if (x<=maxull/10) return (10*x)/y;
// for speed, and to ensure that y>10 to avoid division by 0 later
ull r=y/10;
if (r*10==y) return x/r;
ull ub=x/(r+1); // ub >= 10x div y (without overflow)
ull x10=x*10; // allow overflow
cout<<"ub="<<(asint)ub<<" x10="<<(asint)x10<<" r="<<(asint)r<<" ";
return less_mod_near(x10,ub) ? ub-1 : ub;
// we already handled the 10 evenly divides y case
}
int pdd(ull x, ull y,ull mustbe)
{
ull d=fdd(x,y);
cout << (asint)x << '/' << (asint)y << " = ." << (asint)d << "...";
if (d!=mustbe) cout << " (should be "<<(asint)mustbe<<")";
cout<<endl;
// assert(a==d);
}
int main() {
pdd(0,1,0);
pdd(1,2,5);
pdd(11,101,1);
pdd(10,101,0);
pdd(49,69,7);
pdd(50,69,7);
pdd(48,69,6);
pdd(160,200,8);
pdd(161,200,8);
pdd(159,200,7);
pdd(254,255,9);
}
Output:
0/1 = .0...
1/2 = .5...
11/101 = .1...
10/101 = .0...
ub=7 x10=234 r=6 49/69 = .7...
ub=7 x10=244 r=6 50/69 = .7...
ub=6 x10=224 r=6 48/69 = .6...
160/200 = .8...
161/200 = .8...
159/200 = .7...
ub=9 x10=236 r=25 254/255 = .9...