如果没有“while True”循环,如何绘制对数?

2024-05-16 21:19:11 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我找到了一种方法,使用一个始终正确的while循环,然后在音调低于或高于人类可听到的范围时使用break退出循环

我知道这种循环是一种不好的做法,但是作为一个新手程序员,我想不出如何用正确的方法来实现。如果不使用“while True”,如何实现相同的结果

我已尝试将条件“note>;highest或note<;lowest”放在while循环中,其中“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”


Tags: or方法keytrueifequalnotebreak
2条回答

我注意到你让你的编译器一次又一次地重新做同样的计算,而它们只需要做一次!(这些都可以由您来完成)

您有一个用于注释值的设置公式:note = key * ( 2 ** (1/TET) ) ** i。这可以很容易地反转为i作为note: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,而不管日志的原始基数是什么。这就是为什么我们在i_value函数中除以math.log(2),它给出了N/key的日志基数2

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

最后一个print语句使用*equal_temper注释列表进行“解包”,然后在每个元素之间使用换行符(\n)进行打印

你可以简单地写下

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])

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

相关问题 更多 >