Back to my original idea of using continued fractions. Take, for example, note 60 (Middle C), which has a frequency of 261.6255653005986346778499935 Hz. [261, 1, 1, 1, 2, 27, 3, 1, 3, 2, 1, 2, 5, 4, 1, 1, 6, 1, 1, 3, 17, 2, 1, 6, 4, 1, 2, 5, 2, 2, 1, 1, 2, 1, 1, 20, 3, 4, 3, 3, 3, 5, 1, 2, 1, 29, 1, 7, 3, 1, 1, 1, 1, 3, 3].

We could truncate this list at any point, getting the sequence of approximations 261, 262, 523/2, 785/3, 2093/8, 57296/219, 173981/665, 231277/884, 867812/3317, 1966901/7518, 2834713/10835, 7636327/29188, 41016348/156775, 171701719/656288, 212718067/813063, 384419786/1469351, 2519236783/9629169, 2903656569/11098520, 5422893352/20727689, 19172336625/73281587, 331352615977/1266514668, 681877568579/2606310923, 1013230184556/3872825591, 6761258675915/25843264469, 28058264888216/107245883467, 34819523564131/133089147936, 97697312016478/373424179339, 523306083646521/2000210044631, 1144309479309520/4373844268601, 2811925042265561/10747898581833, 3956234521575081/15121742850434, 6768159563840642/25869641432267, 17492553649256365/66861025714968, 24260713213097007/92730667147235, 41753266862353372/159591692862203, 859326050460164447/3284564524391295, 2619731418242846713/10013285266036088, 11338251723431551299/43337705588535647, 36634486588537500610/140026402031643029, 121241711489044053129/463416911683464734, 400359621055669659997/1530277137082037231, 2123039816767392353114/8114802597093650889, 2523399437823062013111/9645079734175688120, 7169838692413516379336/27404962065445027129, 9693238130236578392447/37050041799620715249, 288273744469274289760299/1101856174254445769350, 297966982599510868152746/1138906216054066484599, 2374042622665850366829521/9074199686632911161543, 7420094850597061968641309/28361505275952799969228, 9794137473262912335470830/37435704962585711130771, 17214232323859974304112139/65797210238538511099999, 27008369797122886639582969/103232915201124222230770, 44222602120982860943695108/169030125439662733330769, 159676176160071469470668293/610323291520112422223077, 523251130601197269355699987/2000000000000000000000000.

Or we could add 1 to the last element of the list, rounding the final denominator up instead of down. This gives us a different (but partially overlapping) sequence: 262, 523/2, 785/3, 1308/5, 2878/11, 59389/227, 231277/884, 405258/1549, 1099089/4201, 2834713/10835, 4801614/18353, 10471040/40023, 48652675/185963, 212718067/813063, 384419786/1469351, 597137853/2282414, 2903656569/11098520, 5422893352/20727689, 8326549921/31826209, 24595229977/94009276, 350524952602/1339796255, 1013230184556/3872825591, 1695107753135/6479136514, 7774488860471/29716090060, 34819523564131/133089147936, 62877788452347/240335031403, 132516835580609/506513327275, 621003395662999/2373634223970, 1667615562956041/6374054313232, 3956234521575081/15121742850434, 6768159563840642/25869641432267, 10724394085415723/40991384282701, 24260713213097007/92730667147235, 41753266862353372/159591692862203, 66013980075450379/252322360009438, 901079317322517819/3444156217253498, 3479057468703011160/13297849790427383, 13957983141674398012/53350990854571735, 47972738311969051909/183364107620178676, 157876198077581553739/603443313715107763, 521601332544713713126/1993694048765501965, 2523399437823062013111/9645079734175688120, 4646439254590454366225/17759882331269339009, 9693238130236578392447/37050041799620715249, 16863076822650094771783/64455003865065742378, 297966982599510868152746/1138906216054066484599, 586240727068785157913045/2240762390308512253949, 2672009605265361234982267/10213105902686977646142, 9794137473262912335470830/37435704962585711130771, 17214232323859974304112139/65797210238538511099999, 27008369797122886639582969/103232915201124222230770, 44222602120982860943695108/169030125439662733330769, 71230971918105747583278077/272263040640786955561539, 203898778281054330414363401/779353416959775155553846, 682927306761268738826368280/2610323291520112422223077.

Or we could ignore the continued fraction stuff altogether and just brute-force the denominators. To avoid any base-specific bias, I'll set the upper bound of the brute-forcing to 2520.

Code: Select all

```
def approximations(x):
x = Fraction(x)
result = {x}
# Continued fraction approximations.
cf = frac_to_contfrac(x)
for i in range(1, len(cf)):
cf_trunc = cf[:i]
result.add(contfrac_to_frac(cf_trunc))
cf_trunc[-1] += 1
result.add(contfrac_to_frac(cf_trunc))
# Brute force
for denominator in range(1, 2521):
numerator = int(denominator * x)
result.add(Fraction(numerator, denominator))
result.add(Fraction(numerator + 1, denominator))
return result
def error_ratio(x, y):
x = Fraction(x)
y = Fraction(y)
return max(x / y, y / x)
def best_approximations(x):
x = Fraction(x)
# Get a list of approximations and sort by denominator,
# then by numerator if there are ties
approx = list(approximations(x))
approx.sort(key=lambda q: (q.denominator, q.numerator))
# Build the list of best approximations
result = []
best_error = float('inf')
for q in approx:
err = error_ratio(q, x)
if err < best_error:
best_error = err
# Only allow one (the best) of each denominator.
if result and q.denominator == result[-1].denominator:
result[-1] = q
else:
result.append(q)
return result
```

So, for Middle C, that gives us the sequence of approximations 262, 523/2, 785/3, 1308/5, 2093/8, 30087/115, 32180/123, 34273/131, 36366/139, 38459/147, 40552/155, 42645/163, 44738/171, 46831/179, 48924/187, 51017/195, 53110/203, 55203/211, 57296/219, 116685/446, 173981/665, 231277/884, 636535/2433, 867812/3317, 1966901/7518, 2834713/10835, 4801614/18353, 7636327/29188, 41016348/156775, 171701719/656288, 212718067/813063, 384419786/1469351, 2519236783/9629169, 2903656569/11098520, 5422893352/20727689, 19172336625/73281587, 331352615977/1266514668, 681877568579/2606310923, 1013230184556/3872825591, 6761258675915/25843264469, 28058264888216/107245883467, 34819523564131/133089147936, 62877788452347/240335031403, 97697312016478/373424179339, 523306083646521/2000210044631, 1144309479309520/4373844268601, 2811925042265561/10747898581833, 3956234521575081/15121742850434, 6768159563840642/25869641432267, 10724394085415723/40991384282701, 17492553649256365/66861025714968, 24260713213097007/92730667147235, 41753266862353372/159591692862203, 859326050460164447/3284564524391295, 2619731418242846713/10013285266036088, 11338251723431551299/43337705588535647, 36634486588537500610/140026402031643029, 121241711489044053129/463416911683464734, 400359621055669659997/1530277137082037231, 2123039816767392353114/8114802597093650889, 2523399437823062013111/9645079734175688120, 7169838692413516379336/27404962065445027129, 9693238130236578392447/37050041799620715249, 288273744469274289760299/1101856174254445769350, 297966982599510868152746/1138906216054066484599, 2374042622665850366829521/9074199686632911161543, 7420094850597061968641309/28361505275952799969228, 9794137473262912335470830/37435704962585711130771, 17214232323859974304112139/65797210238538511099999, 27008369797122886639582969/103232915201124222230770, 44222602120982860943695108/169030125439662733330769, 159676176160071469470668293/610323291520112422223077, 523251130601197269355699987/2000000000000000000000000. That's a lot of fractions; which one do we pick?

For my "overly precise" approximation, I will use

**the first one that, when converted to a float, has the same float representation as the true value**.

Code: Select all

```
def overly_precise(x):
x = Fraction(x)
for q in best_approximations(x):
if float(q) == float(x):
return q
```

For Middle C, it's 2519236783/9629169.

*To be continued...*