|
# this program calculates the Continued Fraction Expansion (CFE) of Champernowne's Constant
|
|
# (in base 10) to HWM #10. For HWM #10, it works in Ruby 1.9.2 but not in 1.9.3.
|
|
# HWMs #5 to #9 still work in 1.9.3.
|
|
# https://docs.google.com/file/d/0B_ZIuCD9HzQtaG5QOEc5dmZ1aFU/edit?pli=1
|
|
# (On the High Water Mark Convergents of Champernowne's Constant in Base Ten).
|
|
# also Google "Champernowne's Constant". Wikipedia or Wolfram MathWorld entries are helpful.
|
|
|
|
|
|
require 'bigdecimal'
|
|
include Math
|
|
|
|
def get_denominator_string(hwm_num) # get the denominator.
|
|
exponent = num_correct_digits(hwm_num - 1) + 2 * (hwm_num - 2) - 3
|
|
mantissa = '4.' + '9' * (hwm_num - 4) + '0' * (hwm_num - 3) + '5'
|
|
mantissa + 'E' + exponent.to_s
|
|
end
|
|
|
|
def num_correct_digits(hwm_num) # get the number of correct digits calculated by the convergent before the given HWM.
|
|
(hwm_num - 3)*10**(hwm_num - 3) - (1..(hwm_num - 4)).inject(0){|sum, int| sum + 10**int} - (hwm_num - 2)
|
|
end
|
|
|
|
puts; puts RUBY_VERSION
|
|
|
|
|
|
hwm = 10 # 5-10. 10 works in 1.9.2 but not in 1.9.3. for 5-9, works in both.
|
|
num_match = 10**(hwm - 4) - 1 # change to 9, 99, 999, etc. for constructing champ number to mult denom by.
|
|
|
|
t = []
|
|
t[0] = Time.now.to_f
|
|
|
|
champ_num_string = '0.'
|
|
for int in 1..num_match # using inject takes about the same amount of time as doing it this way.
|
|
champ_num_string += int.to_s
|
|
end
|
|
champ_num_string += '1' # add a 1 on the end as the first number in 10, 100, 1000, etc, so ceil gives correct numerator.
|
|
t[t.length] = Time.now.to_f
|
|
print "Time to make Champ Number: #{t[t.length - 1] - t[t.length - 2]}\n"
|
|
|
|
denominator = BigDecimal.new(get_denominator_string(hwm))
|
|
champ_num = BigDecimal.new(champ_num_string)
|
|
t[t.length] = Time.now.to_f
|
|
print "Time to make Champ Number and denom into bigdecimal: #{t[t.length - 1] - t[t.length - 2]}\n"
|
|
|
|
n = (champ_num * denominator).ceil
|
|
t[t.length] = Time.now.to_f
|
|
print "Time to calculate and ceil numerator: #{t[t.length - 1] - t[t.length - 2]}\n"
|
|
|
|
File.open("./cn_numer_before_hwm_#{hwm.to_s}_sc_ruby_ver_#{RUBY_VERSION.gsub('.', 'r')}_test.txt", "w") do |f|
|
|
f.puts n
|
|
end
|
|
t[t.length] = Time.now.to_f
|
|
print "Time to write numerator: #{t[t.length - 1] - t[t.length - 2]}\n"
|
|
|
|
d = (denominator + 1).to_i # have to add 1 or it returns infinity for HWM #10.
|
|
d -= 1 # subtract 1 to set it back to what it should be.
|
|
|
|
File.open("./cn_denom_before_hwm_#{hwm.to_s}_sc_ruby_ver_#{RUBY_VERSION.gsub('.', 'r')}_test.txt", "w") do |f|
|
|
f.puts d
|
|
end
|
|
t[t.length] = Time.now.to_f
|
|
print "Time to make denom into integer and write: #{t[t.length - 1] - t[t.length - 2]}\n"
|
|
|
|
####### the numerator and denominator are calculated and stored correctly for all HWMs (#5 through #10) in both 1.9.2 and 1.9.3 so the problem seems to be after this.
|
|
|
|
File.open("./cn_cfe_coeffs_before_hwm_#{hwm.to_s}_sc_ruby_ver_#{RUBY_VERSION.gsub('.', 'r')}_test.txt", "w") do |f|
|
|
num_coeffs = 0 # get CFE coefficients.
|
|
while d != 1 && num_coeffs < 5000 # should stop at 4837 for HWM #10, but it does not in 1.9.3.
|
|
if d == 0
|
|
puts 'error - numerator and denominator not in lowest terms.' # this should never happen as the CFE is guaranteed to be in lowest terms.
|
|
exit
|
|
end
|
|
|
|
q = n / d
|
|
d, n = n - d*q, d # flip n and d. using modulo is slower.
|
|
# print num_coeffs, ' ', q, "\n"
|
|
f.print num_coeffs, " ", q, "\n"
|
|
|
|
if d == 1 # if d=1, n is the last coefficient.
|
|
if num_coeffs % 2 == 0 # last coeff is not 1. we know hwm is on an even term (since calc num is larger than champ num). if num_coeffs is even, we know the last term (n) is not 1.
|
|
f.print num_coeffs + 1, " ", n, "\n"
|
|
else # last coeff is 1.
|
|
f.print num_coeffs + 1, " ", n - 1, "\n"
|
|
f.print num_coeffs + 2, " 1\n"
|
|
end
|
|
end
|
|
|
|
num_coeffs += 1
|
|
end
|
|
end
|
|
t[t.length] = Time.now.to_f
|
|
print "Time to calc and write coefficients: #{t[t.length - 1] - t[t.length - 2]}\n"
|
|
|
|
t[t.length] = Time.now.to_f
|
|
print "Total time: #{t[t.length - 1] - t[0]}\n"
|
|
|
|
|