Longest repeating cycle of numbers

I am trying to find a number less than 1000 that produces the longest string of repeating numbers when it divides 1. I have a list of decimal numbers and need to find the ones with the longest repeating sequence.

That's what I have so far

numbers = [*2..999]
decimal_representations = numbers.map { |number| 1.to_f/number }
decimal_representations.map!(&:to_s)

      

I can create a 3D array using regex. Regex /(.+)\1+/

creates an array of duplicate substrings. I want to find the longest substring, so I used an enumerated function max_by

.

decimal_representations.map! { |decimal| decimal.scan(/(.+)\1+/).max_by(&:length) }.flatten

      

I need to compress my array in order to remove elements nil

decimal_representations.compact!

      

Then I can find out which length was the longest.

decimal_representations.max_by(&:length)

      

I get 0090009009

, but can't figure out which number this decimal value has because I removed nil elements from my array.

Any ideas?

+3


source to share


3 answers


You can do it like this.

code

def longest_repeating_decimal(last)
  n = (3..last).max_by { |i| find_repeating(i).size }
end

def find_repeating(n)
  num = 1
  a = []  
  remainders = {}
  loop do
    d,r = num.divmod(n)
    return '' if r.zero?
    a << d
    return a[remainders[r]..-1].join if remainders.key?(r)
    remainders[r] = a.size
    num = 10*r
  end
end

      

<strong> Examples

n = longest_repeating_decimal(999)
  #=> 983
find_repeating(n).size
  #=> 982 
find_repeating(n)
  #=>   "00101729399796541200...54323499491353" 

require 'bigdecimal'
BigDecimal.new(Rational(1,n),990).to_s('990F')
  #=> "0.00101729399796541200...5432349949135300101729..." 
  #                                           |repeating->

n = longest_repeating_decimal(9_999)
  #=> 9967
find_repeating(n).size
  #=> 9966 

n = longest_repeating_decimal(99_999)
  #=> 99989 (took several minutes) 
find_repeating(n).size
  #=> 99988

      

Hmmm. An interesting picture.

Here are the numbers between 3

and 30

that repeat the decimal places:

def display(n)
  (3..n).each do |i|
    repeat = find_repeating(i)
    (puts "%2d %9s %23.20f" % [i, repeat, 1.0/i]) unless repeat.empty?
  end
end

display(30)
 n  repeating 1.0/n
 3         3  0.33333333333333331483
 6         6  0.16666666666666665741
 7    142857  0.14285714285714284921
 9         1  0.11111111111111110494
11        90  0.09090909090909091161
12         3  0.08333333333333332871
13    769230  0.07692307692307692735
14    714285  0.07142857142857142461
15         6  0.06666666666666666574
17         8  0.05882352941176470507
18         5  0.05555555555555555247
19     52631  0.05263157894736841813
21    476190  0.04761904761904761640
22        45  0.04545454545454545581
23        43  0.04347826086956521618
24         6  0.04166666666666666435
26    384615  0.03846153846153846367
27       370  0.03703703703703703498
28    571428  0.03571428571428571230
29         4  0.03448275862068965469
30         3  0.03333333333333333287

      



Explanation

When you make a long split and come across a remnant you had earlier, you know that the sequence from the earlier remainder will repeat forever, so you stop there and mark the repeating sequence. This is what it does find_repeating

. If 1.0/n

( n

, which is an argument find_repeating

) it repeats digits, a string of repeating digits is returned. If 1.0/n

finite, an empty string is returned.

Besides

You asked, "I get 009009009, but I can't figure out which number this decimal value has ...". (You had an extra zero in the middle, which I assume was a typo.) Here's how to get the number.

1/n                 = 0.009009...
10**3 * (1/n)       = 9.009009...
10**3 * (1/n) - 1/n = 9
(10**3 - 1)/n       = 9
n                   = (10**3 - 1)/9
                    = 111

      

Confirm:

1.0/111 #=> 0.009009...    

      

You will need to use BigDecimal for longer repetition of decimal places.

+2


source


Float

cannot accurately represent most decimal numbers, so using (1.to_f/number).to_s

probably won't give you the expected result. This means your whole algorithm is wrong.


You need a different algorithm. Here's a hint: 1.0 / 7

in math, it produces a decimal character 0.142857142857...

, a repeated sequence 142857

. If you use this division, you will notice what 142857

is the divisor 999999

, which is not a coincidence.



Numbers that are multiples of 2

or 5

need extra attention. The trick is that, for example, 14

( 7 * 2

) or 35

( 7 * 5

) have the same number of repeating sequences in their decimal representation 1.0 / n

.

It's a bit difficult to explain this idea without code. I solved this project Euler problem , but hope you can solve it without looking at my source code .

+4


source


The corresponding number is 111. I figured it out using the response answer:

1 / 0.009009009009009 = 111

By the way, I am not claiming that your answer is correct, I am simply helping you interpret the answer you received. 1/7 digits have a longer repeating sequence.

Real solution to the problem

I actually solved this problem for real. Here is the code / notes I wrote to solve this problem. If you've just read my comments before looking at my code, you should write the code yourself to see what's going on here. If you want to be screwed up, just go to the very bottom to find out what the answer is.

# First, we need to figure out how digits in a decimal representation
# of a fraction get calculated.  We will write a method that prints
# the first 50 decimal digits after the decimal point for the decimal
# representation of a/b, where a and b are integers.
def print_digits_after_decimal(a, b)
  raise ArgumentError if !a.is_a?(Integer)
  raise ArgumentError if !b.is_a?(Integer)

  # We only care about what happening after the decimal point.
  r = a % b

  print "#{a}/#{b} = ."
  50.times do
    r *= 10
    digit = r / b
    print digit
    r = r % b
  end
  puts
end

print_digits_after_decimal(1, 7)
print_digits_after_decimal(11, 28)

# Results:
# 1/7 = .14285714285714285714285714285714285714285714285714
# 11/28 = .39285714285714285714285714285714285714285714285714

# The only thing that changes on each iteration of that loop is r.
# Observe that r is always within the finite range 0..(b-1).  So
# eventually r MUST be equal to a value that it already had before.
# We will write a method to find that first repeated r value.  This
# represents the state of the digit-generating state machine for the
# first state where the decimal digits start a repeating sequence.
def first_repeated_r(a, b)
  raise ArgumentError if !a.is_a?(Integer)
  raise ArgumentError if !b.is_a?(Integer)
  r = a % b

  log = []
  while true do
    return r if log.include?(r)
    log << r
    r = (r * 10) % b
  end
end

# Now use that r value to generate the digits that repeat.  We need to
# call the first_repeated_r method above, and generate digits until we
# see that r value again, and then return those digits as an array.
def repeating_decimal_sequence(a, b)
  r_start = r = first_repeated_r(a, b)

  digits = []
  while true
    r *= 10
    digits << r / b
    r = r % b
    break if r == r_start
  end
  digits
end

# Keep in mind that each r value corresponds to a digit we print out,
# but many different r values can correspond to the same digit.  We
# have not proved that the sequence returned by
# repeating_decimal_sequence doesn't contain a repeated sequence
# inside itself.  We will write a method that takes an array of digits
# and shortens it to the smallest repeating sequence.
def decimal_sequence_deduplicate(digits)
  (1..digits.size).each do |n|
    subsequence = digits[0, n]
    q, r = digits.size.divmod(n)
    if r == 0 && subsequence * q == digits
      return subsequence
    end
  end
  raise "Impossible!"  # math broke
end

p decimal_sequence_deduplicate([1, 5, 8]) # => [1, 5, 8]
p decimal_sequence_deduplicate([1, 5, 1, 5]) # => [1, 5]

# Now we can put these pieces together to answer your question.
answer = (1...1000).max_by do |n|
  decimal_sequence_deduplicate(repeating_decimal_sequence(1, n)).size
end

puts answer   # => 983

# And now we should feel kind of dumb because 983 is simply the
# largest prime number less than 1000, and Euler probably knew that
# without doing this much work!

      

+2


source







All Articles