I'm calculating programatically the frequencies of given musical notes.
Quick intro:
- The musical note A4 has a frequency of 440Hz
- Notes one octave higher are double the frequency of the same note in a lower octave (so A3 is 220Hz, A2 is 110Hz)
- The difference between one note, to the next semitone is log 2 to the base of a 12th.
C3 = B3 x 2 ^ (1/12)
Writing this formula in Ruby, I came up with the following:
# 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
The results I'm getting back are not perfect though. The A notes seem to have rounded a little higher than expected:
-----
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
Note the A frequencies - instead of being 880, 1760, they are slightly higher.
I thought Ruby's Rational was supposed to give accurate calculations and avoid the rounding errors from using floats.
Can anybody explain:
- Why is this result inaccurate?
- How can I improve the above code to obtain a truly accurate result?