python - 如何在没有 "while True"循环的情况下绘制这个对数?

标签 python python-3.x

我一直在尝试绘制十二音阶,从最低到最高可听音调,以赫兹为单位。

我找到了一种方法来做到这一点,使用始终为真的 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”的情况下做到这一点。

最佳答案

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

您的音符值有一个设定方程:note = key * ( 2 ** (1/TET) ) ** i。这可以很容易地反转,以求解作为 note 函数的 i:i = TET * log_2(note/key)。有了这个,并了解注释的上限和下限,我们就可以确定 i 的范围。

代入上限,20000 给出 i=66.07。任何高于此值的值都将导致音符大于上限,因此我们希望采用该值的下限。 i_upper = 66

代入下限 20,得到 i=-53.51。任何低于此值的值都会低于您的下限,因此我们希望采用该值的上限。 i_lower = -53

现在我们要做的就是从 i_lower 循环到 i_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 的原始底是什么。这就是为什么我们在 i_value 函数中除以 math.log(2) —— 它给出了 N/key 的以 2 为底的对数。

字符串之前使用的字母 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) 每个元素之间。

关于python - 如何在没有 "while True"循环的情况下绘制这个对数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55924999/

相关文章:

python - 用于识别 python 中图像上具有相似模式的特定元素/形状的数据结构

python - 如何使用Python的Request包访问API Get的特定元素?

python - 如何压缩两个不同大小的列表?

python - 在python中循环访问字典的元素

python-3.x - pkg_resources.DistributionNotFound : The 'uvloop>=0.14.0' distribution was not found and is required by uvicorn

python - 在 Pandas 中,创建一个相对于组内特定类别的变量

python - 具有多个 "if"条件的双循环

python - 字符串中的连续值,获取索引

python - SQLAlchemy 初始化开销较高

python - 向 gettext 询问有关 Python 中当前语言和翻译源的信息