bod*_*ous 0 ruby math floating-accuracy rational-numbers
我正在以编程方式计算给定音符的频率.
快速介绍:
C3 = B3 x 2 ^ (1/12)在Ruby中编写这个公式,我想出了以下内容:
# Starting from the note A4 (440Hz)
A4 = 440.to_f
# I want the frequencies of each note over the next 3 octaves
number_of_octaves = 3
# There are 12 semitones per octave
SEMITIONES_PER_OCTAVE = 12
current_freq = A4
(number_of_octaves * SEMITIONES_PER_OCTAVE).times do |i|
puts "-----" if i % 12 == 0 # separate each octave with dashes
puts current_freq
current_freq = current_freq * 2 ** Rational('1/12')
end
Run Code Online (Sandbox Code Playgroud)
我回来的结果并不完美.A票据似乎略高于预期:
-----
440.0
466.1637615180899
493.8833012561241
523.2511306011974
554.3652619537443
587.3295358348153
622.253967444162
659.2551138257401
698.456462866008
739.988845423269
783.9908719634989
830.6093951598906
-----
880.0000000000003
932.3275230361802
987.7666025122486
1046.502261202395
1108.7305239074888
1174.6590716696307
1244.5079348883241
1318.5102276514804
1396.9129257320162
1479.9776908465383
1567.981743926998
1661.2187903197814
-----
1760.000000000001
1864.6550460723606
1975.5332050244976
2093.0045224047904
2217.4610478149784
2349.3181433392624
2489.0158697766497
2637.020455302962
2793.825851464034
2959.9553816930784
3135.963487853998
3322.4375806395647
Run Code Online (Sandbox Code Playgroud)
注意A频率 - 而不是880,1760,它们略高.
我认为Ruby的Rational应该提供准确的计算并避免使用浮点数的舍入错误.
谁能解释一下:
我不清楚在这个表达式中是否:current_freq * 2 ** Rational('1/12')Ruby将整个计算保留在Rational领域.在Ruby中,你得到:
2.0.0p195 :001 > current_freq = 440
=> 440
2.0.0p195 :002 > current_freq * 2 ** Rational('1/12')
=> 466.1637615180899
Run Code Online (Sandbox Code Playgroud)
计算产生一个浮点数,而不是一个Rational.如果我们保持Rational,它看起来像:
2.0.0p195 :005 > Rational( current_freq * 2 ** Rational('1/12'))
=> (4100419809895505/8796093022208)
Run Code Online (Sandbox Code Playgroud)
即使你这样做:
2.0.0p195 :010 > Rational(2) ** Rational(1,12)
=> 1.0594630943592953
Run Code Online (Sandbox Code Playgroud)
Ruby从Rational转向浮动.关于Rational的Ruby文档没有清楚地描述这一点,但是给出的例子在将一个有理的分数表示为非整数时表明了这一点.这是有道理的,因为当你将一个有理数给理性(分数,非整数)指数时,你很可能会得到一个无理数.2**(1/12)是其中一个案例.
因此,为了保持准确性,您需要将所有内容保留在Rational领域中,一旦达到无理数,就无法实现.正如Scott Hunter建议的那样,你可以通过一些自定义函数来缩小字段以控制不准确性.目前还不清楚在这种情况下是否值得付出努力.