11
\$\begingroup\$

Starting at 1-TET, give equal temperaments that have better and better approximation of the perfect fifth(just ratio 3/2). (OEIS sequence A060528)

The formal description of the sequence, copied from the OEIS:

A list of equal temperaments (equal divisions of the octave) whose nearest scale steps are closer and closer approximations to the ratios of two tones of musical harmony: the perfect 4th, 4/3 and its complement the perfect 5th, 3/2.

Note that by symmetry, the perfect fourth doesn't matter.

Let's say we know that 3 is in the sequence. The frequencies in 3-TET are:

2^0, 2^⅓, 2^⅔

Where 2^⅔ is the closest logarithmic approximation of 3/2.

Is 4 in the sequence? The frequencies in 4-TET are:

2^0, 2^¼, 2^½, 2^¾

Where 2^½ is the closest approximation of 3/2. This is not better than 2^⅔, so 4 is not in the sequence.

By similar method, we confirm that 5 is in the sequence, and so on.

When given an integer n as input, the output must be the first N numbers of the sequence in order. For example, when n = 7, the output should be:

1 2 3 5 7 12 29

Sequence description by xnor

The irrational constant \$ \log_2(3) \approx 1.5849625007211563\dots\$ can be approximated by a sequence of rational fractions

$$ \frac{2}{1}, \frac{3}{2}, \frac{5}{3}, \frac{8}{5}, \frac{11}{7}, \frac{19}{12}, \frac{46}{29}, \dots$$

A fraction is included in the sequence if it's the new closest one by absolute distance \$ \left| \frac{p}{q} - \log_2(3)\ \right|\$, that is, closer than any other fraction with a smaller or equal denominator.

Your goal is to output the first \$n\$ denominators in order. These are sequence A060528 (table). The numerators (not required) are given by A254351 (table)

Rules:

  1. Do not import the sequence A060528 directly.
  2. The format doesn't matter as long as the numbers are distinguishable. In the example above, the output can also be:

    [1,2,3,5,7,12,29]

  3. As this is a code-golf, the shortest code in bytes wins.

\$\endgroup\$
9
  • 5
    \$\begingroup\$ Hi and welcome to Code Golf SE! We require that all challenges be self-contained, so a description here of the sequence would be a great help. \$\endgroup\$ Commented Sep 24, 2019 at 21:54
  • 5
    \$\begingroup\$ I'm confused by the description from OEIS. It mentions perfect 4th as well (ratio 4/3), but the challenge is about perfect 5ths (ratio 3/2). I think it also needs explanation that the sequence values are the denominators of the rational approximations. \$\endgroup\$
    – xnor
    Commented Sep 24, 2019 at 21:58
  • 5
    \$\begingroup\$ I like the challenge, but I find the stuff added to the description still confusing, not knowing much about music. For instance, I don't know what 1-TET or 4-TET are, and nothing seems to show up on Google. I'll try writing an explanation of how I'd describe this sequence. \$\endgroup\$
    – xnor
    Commented Sep 24, 2019 at 23:06
  • 3
    \$\begingroup\$ @DannyuNDos Ah yes, the 12-tone equal temperament. That's my favourite instrument \$\endgroup\$
    – Jo King
    Commented Sep 25, 2019 at 1:53
  • 2
    \$\begingroup\$ @DannyuNDos Thanks. So the comparison is between 1/2 and log2(1.5), not between 2^(1/2) and 1.5. That should be made clearer in the text \$\endgroup\$
    – Luis Mendo
    Commented Sep 25, 2019 at 9:48

8 Answers 8

5
\$\begingroup\$

05AB1E, 19 18 bytes

µ¯ßNLN/3.²<αßDˆ›D–

Try it online!

µ                      # repeat until counter == input
 ¯                     #  push the global array
  ß                    #  get the minimum (let's call it M)
   N                   #  1-based iteration count
    L                  #  range 1..N
     N/                #  divide each by N
       3.²             #  log2(3)
          <            #  -1
           α           #  absolute difference with each element of the range
            ß          #  get the minimum
             Dˆ        #  add a copy to the global array
               ›       #  is M strictly greater than this new minimum?
                D–     #  if true, print N
                       #  implicit: if true, add 1 to the counter
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice answer, but all I'm wondering right now is why the while-loop has 1-based indices.. :S \$\endgroup\$ Commented Sep 25, 2019 at 12:48
4
\$\begingroup\$

JavaScript (V8), 81 80 78 bytes

-2 bytes thanks Arnauld!

n=>{for(d=g=1;w=Math.log2(3),w+=~(w*g-.5)/g,n--;g++)w*w<d?d=print(g)||w*w:n++}

Try it online!

\$\endgroup\$
0
4
\$\begingroup\$

Wolfram Language (Mathematica), 62 60 58 bytes

Denominator@Table[a=#~Rationalize~Abs[#-a]&@Log2@3,a=1;#]&

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ How many precision? \$\endgroup\$ Commented Sep 25, 2019 at 1:38
  • \$\begingroup\$ @DannyuNDos This function uses exact values, so computations can be done to arbitrary precision. \$\endgroup\$
    – att
    Commented Sep 25, 2019 at 1:39
  • \$\begingroup\$ You win the challenge. \$\endgroup\$ Commented Sep 25, 2019 at 1:48
  • 5
    \$\begingroup\$ @DannyuNDos why accept an answer this quickly? It's also arguably better not to accept an answer at all.. \$\endgroup\$
    – att
    Commented Sep 25, 2019 at 2:03
  • \$\begingroup\$ Regarding the floating-point errors other languages are suffering, I'd like to present an alternative method of alloting score. So hold on. \$\endgroup\$ Commented Sep 25, 2019 at 2:10
2
\$\begingroup\$

Python 2, 92 bytes

E=k=input()
n=0
while k:
 n+=1;e=abs((3.169925001442312*n-1)%2-1)/n
 if e<E:print n;E=e;k-=1

Try it online!

Uses the constant 3.169925001442312 for \$2 \log_2(3)\$. I wasn't sure how many digits of accuracy are required, since the inaccuracy will break the sequence eventually, so I used the full float precision of 2 * numpy.log2(3).

\$\endgroup\$
5
  • 1
    \$\begingroup\$ This gives two extra terms after 665: ..., 665, (1995), (4655), 8286, ... Try it online! \$\endgroup\$
    – Οurous
    Commented Sep 25, 2019 at 1:31
  • \$\begingroup\$ @Οurous Yeah, that's pretty much inevitable sooner or later for any language without infinite precision, though I'm surprised it popped up so early with 32-bit floats as Python uses. I'll wait for the challenge writer to clarify on how far answers need to work. \$\endgroup\$
    – xnor
    Commented Sep 25, 2019 at 7:03
  • \$\begingroup\$ wouldn't it be fewer characters to use 2 * numpy.log2(3) rather than the fully spelled out number? (Or even better, numpy.log2(9)) \$\endgroup\$
    – JDL
    Commented Sep 25, 2019 at 13:28
  • \$\begingroup\$ @JDL that would require this code: from numpy import* and log2(9). \$\endgroup\$ Commented Sep 25, 2019 at 13:34
  • \$\begingroup\$ ah, that is what I get for assuming python works like R and you can write package::function without loading package first! \$\endgroup\$
    – JDL
    Commented Sep 25, 2019 at 13:35
2
\$\begingroup\$

Clean, 128 111 108 bytes

import StdEnv
c=ln 3.0/ln 2.0
?d=abs(toReal(toInt(c*d))/d-c)
$i=take i(iterate(\d=until((>)(?d)o?)inc d)1.0)

Try it online!

Should work up to the limits of Real's 64-bit double precision type.

\$\endgroup\$
2
\$\begingroup\$

MATL, 27 25 bytes

1`@:@/Q3Zl-|X<hY<tdzG-}df

Try it online!

Explanation

1       % Push 1. This initiallizes the vector of distances
  `     % Do...while
  @:    %   Range [1, 2, ..., k], where k is the iteration index, staring at 1
  @/    %   Divide by k, element-wise. Gives [1/k, 2/k, ..., 1]
  Q     %   Add 1, element-wise. Gives [(k+1/k, (k+2)/k, ..., 2]
  3Zl   %   Push log2(3)
  -|    %   Absolute difference, element-wise
  X<    %   Minimum
  h     %   Concatenate with vector of previous distances
  Y<    %   Cumulative minimum
  t     %   Duplicate
  dz    %   Consecutive differences, number of nonzeros. This tells how many
        %   times the cumulative minimum has decreased
  G-    %   Subtract input n. This is the loop condition. 0 means we are done
}       % Finally (execute on loop exit)
  d     %   Consecutive differences (of the vector of cumulative differences)
  f     %   Indices of nonzeros. This is the final result
        % End. A new iteration is executed if the top of the stack is nonzero
        % Implicit display
\$\endgroup\$
2
\$\begingroup\$

Perl 5 (-MPOSIX=log2 -M5.01 -n), 73, 78, 71 bytes

Fixed following comment, may be improved...

-7 bytes thanks to Grimy

$o=abs$d-(0|.5+($d=log2 3)*++$;)/$;;$@=$o,$_-=say$;if!$@|$o<$@;$_&&redo

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ here's 71 \$\endgroup\$
    – Grimmy
    Commented Sep 27, 2019 at 15:36
1
\$\begingroup\$

Raku (Perl 6) (rakudo) (exact), 113 bytes

{$/=(0,2);(grep {$1**$_>(my$d=min map {1/$_ max$_},((2 X**^$_)X*(⅔.FatRat**$_)))**$0&&($/=($_,$d))},1..*)[^$_]}

Attempt This Online!

Raku (Perl 6) (rakudo) (approximate), 77 bytes

{$!=1;(grep {$!>(my$d=min ((^$_ X/$_)X+⅔.log2)>>.abs)&&($!=$d)},1..*)[^$_]}

Attempt This Online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.