如何在没有“ while True”循环的情况下绘制此对数?

时间:2019-04-30 16:13:30

标签: python-3.x

我一直试图以赫兹为单位绘制从最低到最高可闻音高的十二个音阶。

我找到了一种方法,该方法使用始终为true的while循环,然后在音调低于或高于可听见的人为范围时使用break退出循环。

我知道这种循环是不好的做法,但是-作为一个新手程序员-我想不出如何正确执行此循环。如何不使用“ while True”而达到相同的结果?

我尝试将条件“ note>最高或note <最低”放入“ true”当前在while循环中的位置,但随后仅在循环中定义“ note”,因此出现“ NameError:name'note “未定义”错误。

highest = 20000
lowest = 20

key = 440
TET = 12

equal_temper = [key]

i = 1
while True:
  note = key * (2**(1/TET))**i
  if note > highest or note < lowest:
    break
  equal_temper.append(note)
  i += 1

i = 1
while True:
  note = key * (2**(1/TET))**-i
  if note > highest or note < lowest:
    break
  equal_temper.append(note)
  i += 1

equal_tempered = sorted(equal_temper)
for i in range(len(equal_temper)):
  print(equal_tempered[i])

到终端的输出似乎是正确的。它可能会舍入或舍弃,与我所见过的其他表不同。我只想知道如何在不使用“ while True”的情况下做到这一点。

2 个答案:

答案 0 :(得分:1)

您可以简单地写类似

while lowest <= note <= highest:
  ...

通过这种方式,您可以将if语句中的条件反转为while循环的条件,并摆脱硬编码的布尔值。

编辑: 我对您的代码做了一些小的修改,并提出了以下建议:

def get_equal_tempers(multiplier):
    tempers = list()
    note = 20
    i = 1
    while lowest <= note <= highest:
        note = key * (2 ** (1 / TET)) ** (i*multiplier)
        if note > highest or note < lowest:
            break
        tempers.append(note)
        i += 1
    return tempers



highest = 20000 
lowest = 20

key = 440 
TET = 12

equal_temper = [key] 
equal_temper += get_equal_tempers(1) 
equal_temper += get_equal_tempers(-1)

equal_tempered = sorted(equal_temper)
for i in range(len(equal_temper)):
  print(equal_tempered[i])

当我在机器上运行它时,它会产生与您的代码相同的输出。你能检查一下吗?

答案 1 :(得分:1)

我注意到您正在使编译器一次又一次地重新进行相同的计算,而它们只需要执行一次! (它们可以由您完成)。

您为音符值设置了一个方程式:note = key * ( 2 ** (1/TET) ) ** i。可以很容易地将其转换为inote的函数来解决i = TET * log_2(note / key)。有了这个,知道了音符的上下边界,我们就可以确定i的边界了。

插入上限,20000得到i=66.07。高于此值将导致注释超出您的上限,因此我们想以此为底。 i_upper = 66

输入下限20,得到i=-53.51。低于此值的音符将低于您的下限,因此我们希望将此值设为上限。 i_lower = -53

现在我们要做的就是从i_loweri_upper循环,并用音符值填充数组。

此方法避免使用while循环,如果更改任何参数,则很容易泛化,并且只需通过构造即可返回排序后的数组,因此您不必随后对其进行排序。

import math

highest = 20000
lowest = 20

key = 440
TET = 12

def note_value(key, TET, i):
    """ Returns the note value for a given key, TET, and i"""
    return key * (2**(1/TET))**i

def i_value(key, TET, N):
    """ The inverse of note_value. Re-arranged to solve for i."""
    return TET * math.log(N/key) / math.log(2)

notes_above = math.floor(i_value(key, TET, highest))
print(f"Number of notes above = {notes_above}")

notes_below = - math.ceil(i_value(key, TET, lowest))
print(f"Number of notes below = {notes_below}")

print(f"Total number of notes = {notes_below+notes_above+1}")

equal_temper = [ ]
for i in range(-notes_below, notes_above+1):
    # We have to add 1 to notes_above since range is NOT inclusive of the ending term.
    equal_temper.append(note_value(key, TET, i))

print(*equal_temper, sep="\n")

一些注意事项: Log(x)/Log(B)给出X的日志基数B,无论Log的原始基数是多少。这就是为什么我们在math.log(2)函数中除以i_value的原因-它使我们的对数基数为N/key

在字符串之前使用的字母f表示格式字符串,并将{}中的所有内容替换为计算结果。例如,x=5; print(f"My x is {x}")将打印My x is 5。速记功能是python 3.6的新功能。如果您使用的是python 3.6之前的版本,则需要将格式语句替换为较长的版本:print("Number of notes above = {}".format(notes_above))

最后一个打印语句使用*来“解包” equal_temper笔记列表,然后在每个元素之间用换行符(\n)打印它们。