Approximate floating point number with n-digit precision
JavaScript, O(10p) & 72 bytes
r=>p=>{for(a=0,b=1,t=10**p;(a/b*t|0)-(r*t|0);a/b<r?a++:b++);return[a,b]}
It is trivial to prove that the loop will be done after at most O(10p) iterations.
f=
r=>p=>{for(a=0,b=1,t=10**p;(a/b*t|0)-(r*t|0);a/b<r?a++:b++);return[a,b]}
<math xmlns="http://www.w3.org/1998/Math/MathML">
<mrow>
<mn>0.<input type="text" id="n" value="" oninput="[p,q]=f(+('0.'+n.value))(n.value.length);v1.value=p;v2.value=q;d.value=p/q" /></mn>
<mo>=</mo>
<mfrac>
<mrow><mn><output id="v1">0</output></mn></mrow>
<mrow><mn><output id="v2">1</output></mn></mrow>
</mfrac>
<mo>=</mo>
<mn><output id="d">0</output></mn>
</mrow>
</math>
Many thanks to Neil's idea, save 50 bytes.
Haskell, O(10p) in worst case 121 119 bytes
g(0,1,1,1)
g(a,b,c,d)r p|z<-floor.(*10^p),u<-a+c,v<-b+d=last$g(last$(u,v,c,d):[(a,b,u,v)|r<u/v])r p:[(u,v)|z r==z(u/v)]
Try it online!
Saved 2 bytes thanks to Laikoni
I used the algorithm from https://math.stackexchange.com/questions/2432123/how-to-find-the-fraction-of-integers-with-the-smallest-denominator-matching-an-i.
At each step, the new interval is one half of the previous interval. Thus, the interval size is 2**-n
, where n
is the current step. When 2**-n < 10**-p
, we are sure to have the right approximation. Yet if n > 4*p
then 2**-n < 2**-(4*p) == 16**-p < 10**-p
. The conclusion is that the algorithm is O(p)
.
EDIT As pointed out by orlp in a comment, the claim above is false.
In the worst case, r = 1/10**p
(r= 1-1/10**p
is similar), there will be 10**p
steps : 1/2, 1/3, 1/4, ...
. There is a better solution, but I don't have the time right now to fix this.