| Bytes | Lang | Time | Link |
|---|---|---|---|
| 212 | APLNARS | 251006T050639Z | Rosario |
| 061 | Perl 5 p MListUtil=min | 200722T085321Z | Nahuel F |
| 061 | Python 3 | 200722T073112Z | David Fo |
| 060 | R | 200722T082345Z | Kirill L |
| 075 | R | 200725T083134Z | Dominic |
| 066 | Julia | 200724T151232Z | Federico |
| 169 | Python 3.8 | 200722T140113Z | Alexey B |
| 060 | Wolfram Language Mathematica | 200722T135419Z | ZaMoC |
| 087 | Python 2 | 200721T164444Z | iLikeTra |
| 071 | Python 3.8 prerelease | 200722T001125Z | Surculos |
| 078 | Io | 200722T012212Z | user9206 |
| 026 | APL Dyalog Unicode | 200722T021500Z | Bubbler |
| 031 | Charcoal | 200721T231940Z | Neil |
| 149 | Zig 0.6.0 | 200721T205604Z | pfg |
| 015 | Japt v2.0a0 g | 200721T172344Z | Shaggy |
| 011 | Jelly | 200721T183120Z | Jonathan |
| 011 | 05AB1E | 200721T164551Z | Kevin Cr |
APL(NARS), 212 chars
h←{⍬≡r←⍸⍺≥÷1∨¨k←⌽+∘÷\⍵:⍬⋄1≥i←¯2+↑r:k[↑r]⋄2>≢r←i↓k:1↑r⋄2↑r}∘{∞≤∣⍵:⍬⋄m,∇÷⍵-m←⌊⍵}
v←{(i z)←(⌊,(1∘∣))÷/⍎¨⍕¨1∧¨⍵⋄w←({1∧⍵},{÷1∨⍵})⍵[2]⋄k/⍨⍺≥÷1∨¨k←⌽÷/¨{⍎(⍕⍵),'x'}¨¨{⌈w×⍵}¨1,z+0,⍳i}
p←{1≥≢m←⍺h⍵:m⋄m←⍺v m⋄m[↑⍸k=⌊/k←∣m-⍵]}
// +/79 95 38=212
the function 'p' has as input left [⍺] one positive integer (that would be the max denominator) and as input right [⍵] one rational type, and return zilde or a rational type.
It would use the continue fraction expansion of the input ⍵, get from the expansions the 'sum' more near to ⍵ that has denominator less than ⍺, and the 'sum' that follow that, the one more precise it is not matter if denominator is >⍺. For example
1000000 h 3.14159265359x
5419351r1725033 1146408r364913
From this 2 rational numbers find the division of the two numerators among them for obtain a decimal number, in example
5419351 ÷ 1146408
4.727244576
and use the fractional part of it (0.727244576) for find the number that seems to be the fraction that has min abs difference value from ⍵ with denominator ≤ ⍺.
Test:
8 p 1.21x
6r5
1000000 p 3.14159265359x
3126535r995207
12 p 3.14159265359x
22r7
225 p 0.0748947977x
14r187
1000000 p 19.0x
19
100 p 2.7182818x
193r71
22 p 0.8193927511x
9r11
20 p 0.2557463559x
1r4
100 p 0.2557463559x
11r43
The code it seems break for denominators > 100000000000x
⎕fpc←1024
1024÷3.322
308.2480433
80⍕○1v
3.14159265358979323846264338327950288419716939937510582097494459230781640628620900
aa←3.14159265358979323846264338327950288419716939937510582097494459230781640628620900x
10000000000x p aa
10886058930r3465140179
100000000000x p aa
10886058930r3465140179
1000000000000x p aa
597964296r190337947
10000000000000x p aa
5912477861r1882000155
90⍕∣10886058930r3465140179-aa
0.000000000001506760081764004719735822028917648541680158284026944442004048915485730336859483
90⍕∣5912477861r1882000155-aa
0.000000000001515505297419494124190885830197957760107654303699020598498454609419685389130586
Note that 10886058930r3465140179 is a better approssimation of the 'aa' number than 5912477861r1882000155 and it should not be that.
Perl 5 -p -MList::Util=min, 65, 61 bytes
-4 bytes thanks to DomHastings
/ /;$_=min map abs($`-($-=.5+$_*$`)/$_)." $-/$_",1..$';s;.* ;
Python 3, 66 61 bytes
lambda x:Fraction(x).limit_denominator
from fractions import*
The above function takes a floating point number and returns a bound function Fraction.limit_denominator which, in turn, takes the upper bound for the denominator to return a simplified, approximated fraction as requested.
As you can tell, I’m more of an API reader than a golfer.
- minus 5 bytes thanks to ovs
R, 61 60 bytes
With a byte saved by Dominic van Essen.
function(x,d,n=round(1:d*x))c(m<-order((x-n/1:d)^2)[1],n[m])
R, 75 bytes
function(x,d)c((n=rep(0:1,e=d)+(1:d*x)%/%1)[f<-order((x-n/1:d)^2)[1]],f%%d)
Not a competitive answer as it's already beaten by Kirill, but posting for fun anyway.
I didn't think of the round() function, so this approach rounds down & then up to generate a double-length list of candidate numerators, and then finds the index of the closest fraction. Since the index might be in the second (rounded-up) part of the list, the denominator is the index mod the length of the single-length list.
I think it's fair to conclude that the round() function indeed serves a useful role...
Julia, 66 bytes
r(x,m)=minimum((n=Int(round(x*d));(abs(x-n/d),n//d)) for d=1:m)[2]
or
(x,m)->minimum((n=Int(round(x*d));(abs(x-n/d),n//d)) for d=1:m)[2]
Python 3.8, 169 bytes
Maybe the reason why there was no submissions using Farey sequences is that the code appears rather lengthy.
In short, every proper fraction \$\frac{m}{k}\$ in lowest terms appears in Farey sequence of order \$d\$ if and only if \$k\le d\$.
Farey sequences are constructed by taking mediant of neighboring terms of lower order: \$\left(\frac ab,\frac cd\right)\to\frac{a+c}{b+d}\$, starting from \$\left(\frac 01,\frac 11\right)\$.
And the target number is within one of the intervals \$\left[\frac ab,\frac{a+c}{b+d}\right]\$, \$\left[\frac{a+c}{b+d},\frac cd\right]\$, then we take the interval as a current one.
So the algorithm is:
- Take \$\left(\frac ab,\frac cd\right):=\left(\frac 01,\frac 11\right)\$.
- Take \$\frac{m}{k}:=\frac{a+c}{b+d}\$ and compare with target.
- If \$\frac{m}{k}>\$ target, replace \$\frac{a}{b}\$ by \$\frac{m}{k}\$,
- Else replace \$\frac{c}{d}\$ by \$\frac{m}{k}\$.
- If the next denominator \$b+d\$ is no more than denominator limit, repeat from 2.
- Else return nearest from \$\frac ab,\frac cd\$ to the target.
def f(e,n,g,j):
if n==0:return e,1
x=[(0,1),(1,1)]
while True:
(a,b),(c,d)=x
if b+d>j:break
m,k=a+c,b+d
x[m*g>n*k]=(m,k)
m,k=x[2*n/g-a/b>c/d]
return m+e*k,k
Eats (entire_part,proper_numerator,proper_denominator,denominator_limit) and produces (numerator,denominator), like
>>> f(3,141592653589793,10**len('141592653589793'),57)
(179, 57)
P.S. Recursive version is nothing but shorter, even with all whitespace removed:
f=(lambda e,n,g,j,a=0,b=1,c=1,d=1:
n and(
b+d>j and(lambda x,y:(x+e*y,y))(*([(a,b),(c,d)][2*n/g-a/b>c/d]))
or((m:=a+c)*g>n*(k:=b+d))and f(e,n,g,j,a,b,m,k)or f(e,n,g,j,m,k,c,d)
)or(e,1)
)
Wolfram Language (Mathematica), 60 bytes
(t=s=1;While[Denominator[s=Rationalize[#,1/t++]]<#2,j=s];j)&
Python 2, 168, 135, 87 bytes
z=i=1
def f(x,y):exec"r=round(x*i);q=abs(r/i-x)\nif q<z:z=q;t=r;u=i\ni+=1;"*y;print t,u
Thank you all for your recommendations on my first golf!
Python 3.8 (pre-release), 77 71 bytes
-6 bytes thanks to @ovs !
lambda x,n:min([abs(x-(a:=round(x*b))/b),a,b]for b in range(1,n+1))[1:]
Simply try all denominators from 1 to n, saving all results into a list where each element has the form [error, numerator, denominator]. By taking the min of the list, the fraction with the smallest error is selected.
Io, 78 bytes
Port of Surculose Sputum's answer.
method(x,y,Range 1to(y)map(a,list((x-(b :=(a*x)round)/a)abs,b,a))min slice(1))
Io, 93 bytes
method(x,y,list(((q :=(r :=Range 0to(y)map(a,(x-(a*x)round/a)abs))indexOf(r min))*x)round,q))
Explanation (ungolfed):
method(x, y, // Take two operands
r := Range 0 to(y) map(a, // Map in range 0..y (set to r):
(x-(a*x)round/a)abs // |x-round(a*x)/a|
) // (Aka find the appropriate numerator)
q :=r indexOf(r min) // Set q as the 0-index of the smallest number of r
list((q*x)round,q) // Output [numerator,denominator]
) // End function
APL (Dyalog Unicode), 26 bytes
⌊.5+(⊃∘⍋1+|⍨⌊⊢-|⍨)∘÷∘⍳×1,⊣
A dyadic tacit function that takes the decimal number on its left and the max denominator on its right, and gives a 2-element vector of [denominator, numerator].
How it works
⌊.5+(⊃∘⍋1+|⍨⌊⊢-|⍨)∘÷∘⍳×1,⊣ ⍝ Left: x, Right: d
∘÷∘⍳ ⍝ v←[1, 1/2, ..., 1/d]
( |⍨) ⍝ Remainder of x divided by each of v
|⍨⌊⊢- ⍝ Min distance from x to some integer multiple of v
1+ ⍝ Add 1 to treat close enough numbers as same
⍝ Otherwise it gives something like 5/20 due to FP error
⊃∘⍋ ⍝ D←The index of minimum (the optimal denominator)
×1,⊣ ⍝ Exact fraction (D,Dx)
⌊.5+ ⍝ Round both
Charcoal, 31 bytes
Nθ⪫…⮌⌊EEN⌊⁺·⁵×θ⊕κ⟦↔⁻θ∕ι⊕κ⊕κι⟧²/
Try it online! Link is to verbose version of code. Explanation:
Nθ Input decimal as a number
N Input maximum denominator
E Map over implicit range
κ Current index (0-indexed)
⊕ Increment (i.e. 1-indexed)
× Multiplied by
θ Input decimal
⌊⁺·⁵ Round to nearest integer
E Map over results
ι Current numerator
∕ Divided by
⊕κ Current denominator
θ Input decimal
↔⁻ Absolute difference
⊕κ Current denominator
ι Current numerator
⟦ ⟧ Make into list
⌊ Take the minimum (absolute difference)
⮌ Reverse the list
… ² Take the first two entries
⪫ / Join with literal `/`
Implicitly print
I'm not 100% sure that the algorithm is correct, so just in case, here's a 34-byte brute-force solution:
NθFNF⊕⌈×θ⊕ι⊞υ⟦↔⁻θ∕κ⊕ι⊕ικ⟧I⊟⌊υ/I⊟⌊υ
Try it online! Link is to verbose version of code. Very slow, so test case is limited to a denominator of 1000. Explanation:
Nθ
Input the decimal.
FN
Loop over the possible denominators (except 0-indexed, so all of the references to the loop variable have to be incremented).
F⊕⌈×θ⊕ι
Loop until the nearest numerator above.
⊞υ⟦↔⁻θ∕κ⊕ι⊕ικ⟧
Save the fraction difference and the denominator and numerator.
I⊟⌊υ/I⊟⌊υ
Print the numerator and denominator of the fraction with the minimum difference.
Zig 0.6.0, 149 bytes
fn a(e:f64,m:f64)[2]f64{var n:f64=1;var d=n;var b=d;var c=b;while(d<m){if(n/d>e)d+=1 else n+=1;if(@fabs(n/d-e)<@fabs(b/c-e)){b=n;c=d;}}return.{b,c};}
Formatted:
fn a(e: f64, m: f64) [2]f64 {
var n: f64 = 1;
var d = n;
var b = d;
var c = b;
while (d < m) {
if (n / d > e) d += 1 else n += 1;
if (@fabs(n / d - e) < @fabs(b / c - e)) {
b = n;
c = d;
}
}
return .{ b, c };
}
Variable declarations are annoying.
Japt v2.0a0 -g, 15 bytes
mc ×õ ï ñ@ÎaXr÷
mc ×õ ï ñ@ÎaXr÷ :Implicit input of array U
m :Map
c : Ceiling
× :Reduce by multiplication
õ :Range [1,result]
ï :Cartesian product with itself
ñ :Sort by
@ :Passing each pair X through the following function
Î : First element of U
a : Absolute difference with
Xr÷ : X reduced by division
:Implicit output of first pair
Jelly, 11 bytes
Ċ×⁹p÷/ạ¥Þ⁸Ḣ
A dyadic Link accepting the decimal [evaluated as a float] on the left and the denominator limit on the right which yields a pair [numerator, denominator] representing the simplified fraction.
Try it online! Or see the test-suite (big denominator limit cases removed due to inefficiency.)
How?
Ċ×⁹p÷/ạ¥Þ⁸Ḣ - Link: v, d
Ċ - ceil (of the decimal value, v)
×⁹ - multiplied by chain's right argument (denominator limit, d)
p - Cartesian power (d) -> all pairs [[1,1],...,[1,d],[2,1],...,[Ċ×⁹,d]]
(note that any pair representing a non-simplified fraction is to
the right of its simplified form)
Þ - (stable) sort by:
¥ - last two links as a dyad:
/ - reduce by:
÷ - division (i.e. evaluate the fraction)
ạ ⁸ - absolute difference with the chain's left argument (v)
Ḣ - head
05AB1E, 11 bytes
î*LãΣ`/¹α}н
Try it online or verify all test cases (except for the two 1000000 test cases, which take too long).
Explanation:
î # Ceil the (implicit) input-decimal
* # Multiply it by the (implicit) input-integer
L # Pop and push a list in the range [1, ceil(decimal)*int]
ã # Create all possible pairs of this list by taking the cartesian product
Σ # Sort this list of pairs by:
` # Pop and push both values separated to the stack
/ # Divide them by one another
¹α # Get the absolute difference with the first input-decimal
}н # After the sort: leave only the first pair
# (after which it is output implicitly as result)