为什么在使用Ruby Rational时会出现舍入错误?

为什么在使用Ruby Rational时会出现舍入错误?,ruby,math,floating-accuracy,rational-numbers,Ruby,Math,Floating Accuracy,Rational Numbers,我正在用程序计算给定音符的频率 快速介绍: 音符A4的频率为440Hz 高一个倍频程的音符是低一个倍频程中相同音符频率的两倍(因此A3为220Hz,A2为110Hz) 一个音符与下一个半音之间的差别是第2个音符与第12个音符的基音之间的对数差 C3=B3x2^(1/12) 在用Ruby编写这个公式时,我得出了以下结论: # Starting from the note A4 (440Hz) A4 = 440.to_f # I want the frequencies of each note

我正在用程序计算给定音符的频率

快速介绍:

  • 音符A4的频率为440Hz
  • 高一个倍频程的音符是低一个倍频程中相同音符频率的两倍(因此A3为220Hz,A2为110Hz)
  • 一个音符与下一个半音之间的差别是第2个音符与第12个音符的基音之间的对数差
  • C3=B3x2^(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
不过,我得到的结果并不完美。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
注意A频率-它们不是8801760,而是稍高一些

我认为Ruby应该提供精确的计算,并避免使用浮点数时的舍入误差

谁能解释一下:

  • 为什么这个结果不准确
  • 如何改进上述代码以获得真正准确的结果

  • 虽然我确信它精确地表示了1/12(作为分数),但一旦你使用它作为指数,你就回到了浮点,并且有可能得到四舍五入的回报


    我假设您编写自己的幂函数,它检查指数是否为整数,并显式使用乘法;这至少可以解决A的问题。

    虽然我确信它精确地表示1/12(作为分数),但一旦你将它用作指数,你就回到了浮点,并且有可能得到四舍五入的回报


    我假设您编写自己的幂函数,它检查指数是否为整数,并显式使用乘法;这至少可以解决你的A。

    我不清楚在这个表达式中:
    current\u 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
    
    计算产生的是一个浮点,而不是一个有理数。如果我们保持理性,它看起来会是:

    2.0.0p195 :005 > Rational( current_freq * 2 ** Rational('1/12'))
     => (4100419809895505/8796093022208)
    
    即使您这样做:

    2.0.0p195 :010 > Rational(2) ** Rational(1,12)
     => 1.0594630943592953
    
    Ruby从Rational变成了float。Rational上的Ruby文档并没有清楚地描述这一点,但给出的示例显示了将Rational转换为非整数的分数指数时的情况。这是有道理的,因为当你将一个有理数取为一个有理(分数,非整数)指数时,你很可能会得到一个无理数<代码>2**(1/12)就是这种情况之一


    所以为了保持准确性,你需要把所有东西都保持在理性的范围内,一旦你碰到一个无理数,这是不可能的。正如Scott Hunter所建议的,您可以使用一些自定义函数来缩小字段范围,以控制不准确度。目前还不清楚在这种情况下,这是否值得付出努力。

    我不清楚在这个表达式中:
    current\u 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
    
    计算产生的是一个浮点,而不是一个有理数。如果我们保持理性,它看起来会是:

    2.0.0p195 :005 > Rational( current_freq * 2 ** Rational('1/12'))
     => (4100419809895505/8796093022208)
    
    即使您这样做:

    2.0.0p195 :010 > Rational(2) ** Rational(1,12)
     => 1.0594630943592953
    
    Ruby从Rational变成了float。Rational上的Ruby文档并没有清楚地描述这一点,但给出的示例显示了将Rational转换为非整数的分数指数时的情况。这是有道理的,因为当你将一个有理数取为一个有理(分数,非整数)指数时,你很可能会得到一个无理数<代码>2**(1/12)就是这种情况之一


    所以为了保持准确性,你需要把所有东西都保持在理性的范围内,一旦你碰到一个无理数,这是不可能的。正如Scott Hunter所建议的,您可以使用一些自定义函数来缩小字段范围,以控制不准确度。目前还不清楚在这种情况下,这是否值得付出努力。

    回答问题的第二部分:

    如何改进上述代码以获得真正准确的结果

    可以用f=2n/12×440计算频率:

    输出:

    440.0
    466.1637615180899
    493.8833012561241
    523.2511306011972
    554.3652619537442
    587.3295358348151
    622.2539674441618
    659.2551138257398
    698.4564628660078
    739.9888454232688
    783.9908719634985
    830.6093951598903
    880.0
    

    回答问题的第二部分:

    如何改进上述代码以获得真正准确的结果

    可以用f=2n/12×440计算频率:

    输出:

    440.0
    466.1637615180899
    493.8833012561241
    523.2511306011972
    554.3652619537442
    587.3295358348151
    622.2539674441618
    659.2551138257398
    698.4564628660078
    739.9888454232688
    783.9908719634985
    830.6093951598903
    880.0
    

    太好了-谢谢你的解释。我认为,就我而言,它足够精确,可以将所有浮动四舍五入到6点。正如他们所说,对爵士乐来说已经足够接近了。2的第十二个根是一个无理数,它不能用a/b来表示。@Stefan确实是这样,这是我的观点,但更一般地说。太好了,谢谢你的解释。我认为,就我而言,它足够精确,可以将所有浮动四舍五入到6点。正如他们所说,对爵士乐来说已经足够接近了。2的第十二个根是一个无理数,它不能用a/b来表示。@Stefan确实是这样,这是我的观点,但更一般地说。