在音高计算中处理对数时的浮点精度



我正在写一个简单的程序来确定两个音高之间的差异(以美分为单位(;1美分等于半音的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

但在完美的第五局中以大约2美分的差距错过了目标:

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中,它没有:它的比率为27/12≈1.4983070768766815。有了较高音符的适当ET值,你就可以得到预期的700。

>>> cent_difference(659.2551138257398, 440)
700.0

这里发生了什么?

你只是在语调中输入频率间隔,并期望以相同的气质获得结果。。

如果你在公式中加入2^(4/12(的等调和主音第三频率比,你确实得到了400美分的结果(如其他答案和评论所解释的,在浮点精度范围内(。

这里的问题是浮点数使用一组位数来表示任何实数。由于其中有无限多个,而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

所以,没什么不同。我不确定你对第二场比赛的预期结果是什么。如果你跳到WolframAlpha并用1200 * log2(660 / 440)进行任务,如果日志不在那里,似乎就没有干净的方法来写这篇文章——无理数的任何数字表示都会丢失精度。

相关内容

  • 没有找到相关文章

最新更新