簡體   English   中英

在音高計算中處理對數時的浮點精度

[英]Float precision when dealing with logarithms in musical pitch calculations

我正在編寫一個簡單的程序來確定兩個音高之間的差異(以美分為單位); 一分等於半音的 1/100。 由於頻率標度是對數的,而不是線性的,因此最好使用美分來比較音高。 理論上,這是一個簡單的計算:確定兩個頻率之間的分數的公式是:

1200 * log2(pitch_a / pitch_b)

我寫了一小段代碼來自動化這個過程:

import numpy as np
import math

def cent_difference(pitch_a, pitch_b)
     cents = 1200 * np.abs(math.log2(pitch_a / pitch_b))
     return cents

當我給程序八度音程時,這非常有效:

In [28]: cent_difference(880, 440)
Out[28]: 1200.0

......但在完美的五分之一上錯過了大約兩美分:

In [29]: cent_difference(660, 440)
Out[29]: 701.9550008653875

......並且隨着我的前進而變得越來越糟,在主要三分之一上丟失了大約 14 美分:

In [30]: cent_difference(550, 440)
Out[30]: 386.31371386483477

這都是浮點精度的廢話嗎? 為什么完美的第五個例子高估了美分,而主要的第三個例子低估了美分? 這里發生了什么?

非常感謝任何幫助!

您遇到的問題在於 Python 的float類型的准確性,而在於音樂中的平等氣質音調之間的差異。

>>> cent_difference(660, 440)
701.9550008653874

這是假設 P5 間隔代表 3/2 的頻率比。 但在 12-ET 中,它沒有:它的比率為 2 7/12 ≈ 1.4983070768766815。 使用適當的高音 ET 值,您確實會得到預期的 700。

>>> cent_difference(659.2551138257398, 440)
700.0

這里的問題是浮點數使用一組位數來表示任何實數。 由於 32 位浮點數(充其量)有無限多個這些值,並且只有 2**32 個值,因此您可以看到將如何有效地逼近無限多個實數。 如果您繼續使用這些近似值進行計算,就會發生錯誤。

您也不必使用大數或長數來遇到一個。 我的最愛:

>>> .1 + .1 + .1
0.30000000000000004

您可以使用更准確的類型,以犧牲一些速度為代價使用更好的表示(有時使用速度較慢但不太可能引入錯誤的操作)。

例如Decimal ,但請確保使用整數來定義它們:

>>> .1 + .1 + .1
0.30000000000000004
>>> from decimal import Decimal
>>> Decimal(.1) + Decimal(.1) + Decimal(.1)
Decimal('0.3000000000000000166533453694')
>>> Decimal (1)/Decimal(10) + Decimal(1)/Decimal(10) + Decimal(1)/Decimal(10)
Decimal('0.3')

如果您的問題存在,最好的解決方案是完全避免浮點數學。

順便說一句,這是您使用Decimal的問題:

from decimal import Decimal, Context


def cent_difference(pitch_a, pitch_b, ctx):
    ratio = ctx.divide(pitch_a, pitch_b)
    cents = Decimal(1200) * ctx.copy_abs(ratio.ln(ctx) / Decimal(2).ln(ctx))
    return cents


ctx = Context(prec=20)
print(cent_difference(Decimal(880), Decimal(440), ctx))
print(cent_difference(Decimal(660), Decimal(440), ctx))

結果:

1200
701.95500086538741774000

所以,沒有那么不同。 我不確定您對那里的第二個結果的期望。 如果您跳到 Wolfram Alpha 並使用1200 * log2(660 / 440)對其進行任務,則在沒有日志的情況下似乎沒有干凈的方法來編寫它 - 任何以無理數的數字表示的精度都將丟失.

這里發生了什么?

您正在以正確的語調輸入頻率間隔,並期望以相同的氣質獲得結果。 .

如果您將 2^(4/12) 的等溫大三度頻率比輸入您的公式,您確實會得到 400 美分的結果(在浮點精度范圍內,如其他答案和評論所述)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM