[QUIZ] Happy Numbers (#93)

H

Hans Fugal

Paul said:
As I understand the Wolfram article, an unhappy number never hits 1 as a
result, whereas a happy number eventually hits 1:

What you have described here is the halting problem. Good luck with that.
"Unhappy numbers have eventually periodic sequences of s(sub)i which never
reach 1."

And what stops it from being a 1x10^50 length period, or any arbitrary
length?
The quiz item emphasizes a criterion that is only mentioned in passing on
the Wolfram page, that is, there are degrees of happiness, and a number
that has many happy predecessors is, umm, more happy. So a relatively large
number that eventually results in 1, but with a lot of steps along the way
(therefore more happy ancestors), is happier.

And what the quiz neglected to mention is that there is an easy test for
unhappy number, which the mathworld page enumerates:

Iterating this sum-of-squared-digits map always eventually
reaches one of the 10 numbers 0, 1, 4, 16, 20, 37, 42, 58, 89,
or 145 (Sloane's A039943; Porges 1945).

So if you hit one of those unhappy numbers you know you're in an unhappy
loop.
 
P

Phrogz

Hans said:
And what the quiz neglected to mention is that there is an easy test for
unhappy number, which the mathworld page enumerates:

Iterating this sum-of-squared-digits map always eventually
reaches one of the 10 numbers 0, 1, 4, 16, 20, 37, 42, 58, 89,
or 145 (Sloane's A039943; Porges 1945).

So if you hit one of those unhappy numbers you know you're in an unhappy
loop.

IMO, that's an unnecessary spoiler (which is why I didn't look at the
Wolfram page). You can figure it out on your own without a 'cheat
sheet' of numbers.
 
W

William Crawford

Hans said:
Iterating this sum-of-squared-digits map always eventually
reaches one of the 10 numbers 0, 1, 4, 16, 20, 37, 42, 58, 89,
or 145 (Sloane's A039943; Porges 1945).

As long as we're noting strategy, the site also noted that 16 and 61 are
identical in terms of the next number. Any set of digits can be
scrambled any which way and it won't matter. 61 will eventually work
around to 16 also. (As shown by the proof of 3, earlier.)
 
S

Sander Land

What you have described here is the halting problem. Good luck with that.

Something which reduces to HP is not equivalent to HP, only if you can
reduce HP to this problem is it equivalent to HP/undecidable.
And what stops it from being a 1x10^50 length period, or any arbitrary
length?

Basic math does.
number of length 100 : 99999...., next step = 100*9^2 = 8100, i.e.
large numbers always go down _a lot_, and therefore cannot be part of
a cycle.
Proving this for n >= 243 (or even smaller n) is left as an exercise
for the reader ;)
 
J

Jacob Fugal

And what stops it from being a 1x10^50 length period, or any arbitrary
length?

The period cannot be any larger than 1000. The largest period is
probably quite a bit smaller than this, but this is a upper bound.
Why?

Some definitions, first.

Let's define g(x) as the function that takes a number to it's
successor. For example, g(42) = 4^2 + 2^2 = 20.

For a variable x, we will denote the result of applying our function
as x'. That is, x' = g(x).

Let Mi = 10^i - 1 for all i. For example, M4 = 9999. Each Mi is the
number made up of i nines. Mi' is then 81 * i.

Let Qi = { x | M(i-1) < x <= Mi }. For example, Q4 is the range of
integers from 1000 to 9999. It's easy to see that the union of all
Qi's cover the natural numbers and that they are all disjoint. So the
set of all Qi's is a partitioning of the natural numbers.

For each x in Qi, it is easy to see that x' <= Mi'.

Now, take any i >= 4. For all x in Qi, x' <= Mi' = 81 * i. But 81 * i
< 10^(i-1) (see below), so 81 * i <= M(i-1), and x' <= M(i-1) for all
x in Qi. But since x > M(i-1) by our choice, we know that x' < x. This
is true for *all* x > 999.

So, for those of you glossing over the math, the conclusion is that
applying the "happy function" to any number greater than or equal to
1000 will necessarily result in a smaller number.

Since the sequence can't loop if we're constantly decreasing (until we
get down to 999 or less), none of the numbers in a period can be
greater than 999 -- there's no way to get back *up* to any of those
numbers.

So, for any loop resulting from a number, the space of numbers liable
to be in that loop is no larger than 1000 number (0 through 999). So
no loop can have a period greater than 1000.

Jacob Fugal
 
H

Hans Fugal

Phrogz said:
IMO, that's an unnecessary spoiler (which is why I didn't look at the
Wolfram page). You can figure it out on your own without a 'cheat
sheet' of numbers.

This isn't a math quiz. It's a programming quiz.
 
J

Jacob Fugal

Now, take any i >= 4. For all x in Qi, x' <= Mi' = 81 * i. But 81 * i
< 10^(i-1) (see below), so 81 * i <= M(i-1), and x' <= M(i-1) for all
x in Qi. But since x > M(i-1) by our choice, we know that x' < x. This
is true for *all* x > 999.

And here's the "below" referred to (I forgot it earlier). :)

Remember that i >= 4. Let's take i = 4 as a basis case.

81 * 4 = 324 < 1000 = 10^(4-1)

Now, assume the hypothesis for some i >= 4. We will prove the
hypothesis continues to hold for j = i + 1.

Since 1/9 < i; 81 < 9 * 81 * i.
Adding 81 * i to both sides of that inequality we get:
81 * j < 10 * 81 * i

From the other side, we can start with the inequality for i (81 * i <
10^(i-1)) and multiply both sides by 10 to get:
10 * 81 * i < 10^(j-1)

Combining those two inequalities, we have: 81 * j < 10^(j-1).

Isn't induction great? :)

Jacob Fugal
 
H

Hans Fugal

Jacob said:
The period cannot be any larger than 1000. The largest period is
probably quite a bit smaller than this, but this is a upper bound.
Why?

So, for those of you glossing over the math, the conclusion is that
applying the "happy function" to any number greater than or equal to
1000 will necessarily result in a smaller number.

Since the sequence can't loop if we're constantly decreasing (until we
get down to 999 or less), none of the numbers in a period can be
greater than 999 -- there's no way to get back *up* to any of those
numbers.

So, for any loop resulting from a number, the space of numbers liable
to be in that loop is no larger than 1000 number (0 through 999). So
no loop can have a period greater than 1000.

And that, my friends, is what stops it from being a 1x10^50 length
period, or any arbitrary length.

If the intent of the quiz was to be mathemeticians and figure all this
mathy stuff out, I apologize for dragging it into the open.
 
W

William Crawford

Paul said:
Another example is non-Euclidean geometry, which was an impractical,
exotic
plaything for about 100 years, until general relativity came along and
required it. Without non-Euclidean geometry, Einstein wouldn't have been
able to express GR at all.

Prior to that, few would have guessed that the universe isn't Euclidean.

Wait, are you suggesting that in a hundred years, Happy Numbers could
prove the universe is... Happy?
 
K

Karl von Laudermann

Here's my solution. Writing a method that can determine whether a number is
happy, and how happy it is, is fairly simple. Once the method exists, it's
fairly trivial to write short programs that use the method to determine the
happiness of a number, or to find the highest happy number or the happiest
number in a range, as requested by the quiz. But the Ruby Quiz generally
requests that you write a program, not a single method, so I decided to write a
program that can perform all of these tasks, depending on the input parameter.
And handle bases other than ten if desired, to boot.

Once I decided to do that, it made sense to optimize the method over multiple
runs, by memoizing results, and taking algorithmic shortcuts based on previously
memoized results. So my get_happy method is a bit more complicated than it was
originally, due to the optimizations.

Of course, once I added optimizations, I introduced bugs. They were subtle and a
bit tricky to track down. But they basically boiled down to this question: Is 1
a happy number, and if so, how happy? It's obvious that when you perform one
iteration of the happiness algorithm, the next number in the sequence has a
happiness value of one less than the current number. For example, take the
sequence used in the quiz description. It starts with 7, which is finally stated
to have a happiness value of 4. The remaining numbers in the sequence, 49, 97,
130, and 10, thus have happiness values of 3, 2, 1, and 0 respectively.

So, is 1 happy? If the definition of a happy number is that the algorithm
evenually reaches 1, then yes it is. What is its happiness value? It could
arguably be 0, because the algorithm goes to 1 right away, without generating
any other happy numbers. But, any number with a happiness value of 0, such as
10, has 1 as its next iterated value, which means that, according to the
paragraph above, 1 should have a happiness value of 1 less than 0, which would
be -1. So is 1's happiness value 0 or -1?

I guess it's an arbitrary choice. But until I realized what was going on, I had
a bug in which a number's happiness value would either be correct, or 1 higher
than correct, depending on whether or not it was being calculated based on a
previous memoized intermediate value. I had originally set 1's happiness value
to 0, but this caused 10's value to be calculated as 1 instead of 0, because it
was 1 higher than the happiness value of the next number in the sequence, which
was of course 1, whose happiness is 0. This happened only when 10's happiness
value was memoized during another number's sequence, but not when 10 itself had
been passed into the get_happy method. Then I naively changed 1's happiness
value to -1, to try to fix this. But this didn't work either, since -1 is my
magic value meaning "unhappy", so all numbers were determined to be unhappy
since 1's memoized value returned as -1 in the first optimization. So I changed
1's happiness value back to 0, and unconditionally decreased all numbers'
happiness values by 1, which also turned out to be wrong.

When I finally understood what was going on, I realized that the correct fix was
to add the "(temp != 1)" conditional in the first "if" statement, and the "ret
-= 1" line if the algorithm has iterated all the way to 1. At this point, 1's
happiness value isn't actually used in the algorithm for computing any other
number's happiness. It's only ever used if get_happy is called on the value 1
itself. And at last, the program works! (At least, I'm pretty sure it does :) )

#!/usr/bin/env ruby
#
# =Description
#
# This program determines the happiness of a number, or the happiest number and
# highest happy number in a range of numbers.
#
# A number's happiness is determined as follows: Sum the squares of the number's
# individual digits. Repeat this process with the result, until a value of 1 is
# reached, or until a value is repeated, thus indicating a loop that will never
# reach 1. A number for which 1 is reached is "happy". The number of other
# numbers generated besides 1 and the original number is its happiness value.
#
# =Usage
#
# happy.rb num1[-num2][:base]
#
# happy.rb takes a single argument. If the argument is a single number, that
# number's happiness value is displayed, or the number is said to be unhappy.
# If the argument is a range of numbers, such as "1-400", the happiness value of
# the happiest number (lowest number breaking ties) in that range is returned.
# If the argument ends with a colon and a number, such as "50:8" or "1-100:2",
# the number after the colon specifies the base of the first number(s). An
# unspecified base implies base ten.

require 'rdoc/usage'

#==============================================================================
# ----- Global variables -----
#==============================================================================

$hap_map = {} # Hash for memoization of happiness values

#==============================================================================
# ----- Instance methods -----
#==============================================================================
class String
# Indicates whether the string is a valid number of the specified base.
def is_num_of_base?(base)
# sub() call removes leading zeros for comparison
self.sub(/\A0+/, '').downcase == self.to_i(base).to_s(base).downcase
end
end

class Integer
# Pretty-print string including base, if base is not 10
def pretty(base)
self.to_s(base) + ((base == 10) ? "" : " (base #{base})")
end
end

#==============================================================================
# ----- Global methods -----
#==============================================================================

# This method returns the happiness value of the given number. A value of -1
# indicates that the number is unhappy.
def get_happy(num, base=10)
$hap_map[num] = 0 if num == 1 # Handles trivial case
return $hap_map[num] if $hap_map[num]

ret = 0
done = false
inters = []
temp = num

until done
digits = temp.to_s(base).split(//).map{|c| c.to_i(base)}
temp = digits.inject(0) {|sum, d| sum + d**2}
ret += 1

if (temp != 1) && $hap_map[temp]
# Optimization; use knowledge stored in $hap_map
if $hap_map[temp] == -1
ret = -1
done = true
else
ret += $hap_map[temp]
done = true
end
else
if temp == 1
ret -= 1 # Don't count 1 as an intermediate happy number
done = true
elsif inters.include?(temp)
ret = -1
done = true
else
inters << temp
end
end
end

$hap_map[num] = ret

# Optimization
if ret == -1
# If num is not happy, none of the intermediates are happy either
inters.each {|n| $hap_map[n] = -1}
else
# If num is happy, each intermediate has a happiness value determined by
# its position in the array
inters.each_index {|idx| $hap_map[inters[idx]] = (ret - 1) - idx}
end

return ret
end

# nums is a range of integers. This method returns two values: the happiest
# number, and the highest happy number, in the range. Two nil values will be
# returned if there are no happy numbers in the range.
def get_superlatives(nums, base)
happiest_num = nil
happiest_ness = nil
highest = nil

nums.each do |n|
happy = get_happy(n, base)
next if happy == -1
highest = n

if (!happiest_ness) || (happy > happiest_ness)
happiest_num = n
happiest_ness = happy
end
end

return happiest_num, highest
end

#==============================================================================
# ----- Script start -----
#==============================================================================

if ARGV.size != 1
RDoc.usage('Usage', 'Description')
end

# Parse arg
ARGV[0] =~ /\A([\d\w]+)(?:\-([\d\w]+))?(?::(\d+))?\Z/
num1, num2, base = $1, $2, $3

# Ensure legal arg
RDoc.usage('Usage', 'Description') unless num1

# Fill in defaults
base = 10 unless base
num2 = num1 unless num2

# Convert numbers from strings to numeric values
base = base.to_i

[num1, num2].each do |s|
unless s.is_num_of_base?(base)
puts "Error: #{s} is not a valid base #{base} number"
exit
end
end

num1 = num1.to_i(base)
num2 = num2.to_i(base)

# Calculate and print results
if num1 == num2
happiness = get_happy(num1, base)

print num1.pretty(base)

if happiness == -1
print " is not happy.\n"
else
print " has a happiness of #{happiness}\n"
end
else
if num1 > num2
num1, num2 = num2, num1
end

happiest, highest = get_superlatives((num1..num2), base)

if !highest
puts "None of those numbers are happy."
else
puts "The happiest number is " + happiest.pretty(base) +
", with a happiness of #{get_happy(happiest, base)}"

puts "The highest happy number is " + highest.pretty(base) +
", with a happiness of #{get_happy(highest, base)}"
end
end

--
Karl von Laudermann - karlvonl(a)rcn.com - http://www.geocities.com/~karlvonl
#!/usr/bin/env ruby
require "complex";w=39;m=2.0;w.times{|y|w.times{|x|c=Complex.new((m*x/w)-1.5,
(2.0*y/w)-1.0);z=c;e=false;49.times{z=z*z+c;if z.abs>m then e=true;break;end}
print(e ?" ":"@@");puts if x==w-1;}}
 
P

Phrogz

Here are my two solutions. Both take arbitrary bases. Neither counts
the number of steps between a number and its happiness. The hash-based
one is based on the auto-memoizing idea previously discussed on this
list for a speedy fibonacci calculation.

The core of both calculations is calculating the next happy step via:
num.to_s(base).split('').map{ |c| c.to_i(base)**2 }.inject{ |s,i| s+i }

class Integer
@@happysteps = Hash.new{ |k,v| k[v] = {} }
def happy?( base=10 )
seen = {}
num = self
until num==1 or seen[ num ]
seen[ num ] = true
num = num.to_s(base).split('').map{ |c| c.to_i(base)**2 }.inject{
|s,i| s+i }
end
num == 1
end
end

happy = Hash.new{ |h1,base|
h1[ base ] = Hash.new{ |h2, n|
if n == 1
h2[ 1 ] = true
else
h2[ n ] = :not_happy
sum_of_squares = n.to_s(base).split('').map{ |c| c.to_i(base)**2
}.inject{ |s,i| s+i }
if sum_of_squares == 1
h2[ n ] = true
else
subn = h2[ sum_of_squares ]
if subn == true
h2[ n ] = true
elsif subn == false || subn == :not_happy
h2[ n ] = h2[ sum_of_squares ] = false
end
end
end
}
}


range = 1..1000
puts "How many Happy numbers between #{range}?"
3.upto(36){ |base|
puts "Base #{base}: #{range.select{|i| happy[ base ][ i ] }.length}
happy numbers."
puts "Base #{base}: #{range.select{|i| i.happy?( base ) }.length}
happy numbers."
}
 
K

Ken Bloom

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion. Please reply to the original quiz message,
if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Shane Emmons

Write a program that tells whether a given integer is happy. A happy number is
found using the following process: Take the sum of the squares of its digits,
and continue iterating this process until it yields 1, or produces an infinite
loop.

For example the number 7:

7^2 = 49
4^2 + 9^2 = 97
9^2 + 7^2 = 130
1^2 + 3^2 + 0^2 = 10
1^2 + 0^2 = 1

If a number is not happy than it is obviously unhappy. Now that you have this
program, what is the largest happy number you can find? What is the happiest
number between 1 and 1,000,000. I define the happiest number as the smallest
number that finds the most other happy numbers with it, i.e. 7 found four other
numbers (49, 97, 130, and 10) making it a rank 4 in happiness.

If you find all these examples trivial, write you program so that it will find
happy numbers in other bases such as base 2 or 16. From there you can extend the
program so that it finds happy bases (other than 2 and 4). A happy bases is a
base where all numbers are happy. Good luck.

require 'enumerator'
require 'jcode'


module Happy
#1 is a success terminator, from Wolfram's MathWorld
FAIL_TERMINATORS=[0, 4, 16, 20, 37, 42, 58, 89, 145]

def internal_happy? number
return 0 if number==1
return false if FAIL_TERMINATORS.include? number
it=Enumerable::Enumerator.new(number.to_s,:each_char)
newnumber=it.inject(0) { |partial_sum,char| partial_sum+(char.to_i)**2 }
x=happy?(newnumber)
return x+1 if x
return false
end

@@memo=Hash.new

def happy? number
return @@memo[number] || @@memo[number]=internal_happy?(number)
end
end

include Happy

#there is no largest happy number because any 10**n is happy for any n.
#since ruby can represent all integers, there's no "largest number I can
#find" (given enough RAM)

#to find the happiest number between 1 and 1_000_000, we use the
#following code (which takes advantage of the memoization that I have
#included)

minhappy=[]
1_000_001.times do |n|
puts "Progress #{n}" if n%1000==0
if x=happy?(n)
if minhappy[x]==nil or minhappy[x]>n
minhappy[x]=n
end
end
end

puts minhappy.last

#after a long time running, this prints that
#the happiest number is 78999

#by clearing the memoization hash and adding a strategically placed
#puts, I can see this computes happiness for the following
#numbers: [78999, 356, 70, 49, 97, 130, 10, 1]

--Ken Bloom
 
S

Sander Land

I solved the question of the happiness of 1 by simply giving 10 and
such a happiness of 2, and 7 a happiness of 5.
This doesn't matter for determining the happiest number anyway, and is
a bit more consistent.

For finding the happiest numbers it only searches numbers with non
decreasing digits (eg. 123 but not 312 and 321).
This speeds up the search a lot, it can handle searching up to 10^10 in seconds.

It can also search for happy bases, because of this my solution has to
work for any base and is a bit messy as to_s is useless for this and
recursion is impossible for bases above 250 or so (stack overflow and
such).
To speed up searches it doesn't clear the cache from previous bases,
so memory uses increases until 300Mb at base 3000 or so.

Anyway, the world is a better place now that we know there are no
happy bases under 3202 ;)

Usage:
happy.rb find [base] - find the happiest number under base^7
happy.rb without parameters: search for happy bases


Code:


class Array
def sum
inject(0){|a,b| a+b}
end
end

class Integer

def to_digits(base)
return [self] if self < base
(self/base).to_digits(base) << self%base
end

def happy_function
to_digits($base).map{|d| d ** 2}.sum
end

def happiness
num = self
chain = [num]
until num == 1 || num.cached_happiness == -1
num.cached_happiness = -1
chain << num = num.happy_function
end
if num == 1
chain.shift.cached_happiness = chain.size until chain.empty?
end
self.cached_happiness
end

def happy?
happiness >= 0
end

protected
def cached_happiness
return 0 if self==1
(@happiness||={})[$base]
end

def cached_happiness=(val)
(@happiness||={})[$base] = val
end
end

def nondec_nums(len,min=0,n=0,&b) # yields all numbers with
non-decreasing digit sequences of length <= len
if len==0
yield n
else
[*min...$base].each{|m| nondec_nums(len-1, m ,n * $base + m,&b) }
end
end

maxn = maxh = 1
s = Time.now

if ARGV[0] == 'find'
$base = (ARGV[1] || 10 ).to_i
MAXLEN = 7
puts "searching happiest number < #{$base**MAXLEN} in base #{$base}"
max_n, max_h = 1,0
nondec_nums(MAXLEN) {|n| # length 7 / up to 9,999,999
if n.happiness > max_h
max_n, max_h = n, n.happiness
puts "n=#{n}\th=#{max_h}\tdigits=#{n.to_digits($base).inspect}"
end
}
else
puts "searching for happy bases, press ctrl-c to quit"
(2..1_000_000).each {|$base|
len = 3 # len * (base-1)^2 < b^len - 1 for len >= 3 and any base
max = $base**len - 1 # upper bound for when \forall n>=max
n.happy_function < n => if all numbers of up to and including this
length are happy then all numbers are
max -= $base**(len-1) while max.happy_function < max # further
decrease upper bound, for base 10 this is : 999, 899, 799, etc
max += $base**(len-1) # previous loop always does 1 step too much
happy_base = true
min_unhappy = nil
nondec_nums(len) {|n|
if !n.happy? && n>0
min_unhappy = n
happy_base = false
break
end
break if n > max
}
puts happy_base ? "base #{$base} is a happy base!" : "base
#{$base} is not a happy base because #{min_unhappy} is unhappy."
}
end
 
S

Sander Land

For a little more speed, try instead:

class Array
def sum
inject{ |a,b| a+b }
end
end

Is that really so much faster? Worth breaking on empty arrays?
Just had to test if there was any performance difference, results:

user system total real
inject(0) 20.320000 5.430000 25.750000 ( 34.486938)
inject 20.450000 5.350000 25.800000 ( 30.152165)
inject &:+ 37.860000 5.690000 43.550000 ( 45.670349)
each 11.130000 3.460000 14.590000 ( 15.042142)
C 0.020000 0.000000 0.020000 ( 0.019815)

so inject(0) vs inject doesn't really matter.
code: http://pastie.caboo.se/11534 (and yes i know the C code doesn't
handle bignums)

@robert: you mean the thread "for performance, write in C" ? ;)
 
Ã

Éric DUMINIL

Hi!

I'd just like to post my isHappy? method:


class Integer
def isHappy?
return to_s.split(//).collect{|digit| digit.to_i**2}.inject{|sum, n| sum +
n }.isHappy? while self!=1
true
rescue
false
end
end

puts
115485454654987986246476765451256546545241654555555555555555555555555555555555554125665146454122345444487.isHappy?
true

This method may return false negative (if happiness>maximum stack level),
though I doubt no one will ever find one!

Thanks for the quiz,

Eric
 
H

Hans Fugal

I wrote it and then added some lookup table optimizations which resulted
in a 1.5 speedup when executed over the numbers 1 through 10,000.

First the naive:

#!/usr/bin/ruby
# Ruby happy number quiz solution. September 2006
# Hans Fugal

class Happy
def initialize
@happy_numbers = { 1 => 0 }
end

def happy(n)
return true if n == 1

x = n
rank = 0
loop do
sum = 0
while x > 0
x, r = x.divmod(10)
sum += r**2
end

rank += 1

if [0, 1, 4, 16, 20, 37, 42, 58, 89, 145].include?(sum)
if sum == 1
@happy_numbers[n] = rank
return true
else
return false
end
end

x = sum
end
end

def rank(x)
raise ArgumentError, "#{x} is unhappy." unless happy(x)
return @happy_numbers[x]
end
end

haphap = Happy.new
ARGF.each_line do |l|
l.scan(/\d+/) do |token|
x = token.to_i
if haphap.happy(x)
puts "#{x} is happy with rank #{haphap.rank(x)}"
end
end
end

Now the optimized:

#!/usr/bin/ruby
# Ruby happy number quiz solution. September 2006
# Hans Fugal

require 'set'

class Happy
def initialize
@happy_numbers = { 1 => 0 }
@unhappy_numbers = Set.new
end

def happy(x)
return true if @happy_numbers.has_key?(x)
return false if @unhappy_numbers.include?(x)

path = [x]
loop do
sum = 0
while x > 0
x, r = x.divmod(10)
sum += r**2
end

if @unhappy_numbers.include?(sum)
return false
elsif @happy_numbers.has_key?(sum)
r = @happy_numbers[sum]
path.each_with_index do |x,i|
@happy_numbers[x] = r + path.size - i
end
return true
end

path.push sum

if [0, 1, 4, 16, 20, 37, 42, 58, 89, 145].include?(sum)
if sum == 1
s = path.size
path.each_with_index do |x,i|
@happy_numbers[x] = s - i - 1
end
return true
else
path.each do |x|
@unhappy_numbers.add x
end
return false
end
end

x = sum
end
end

def rank(x)
raise ArgumentError, "#{x} is unhappy." unless happy(x)
return @happy_numbers[x]
end
end

haphap = Happy.new
ARGF.each_line do |l|
l.scan(/\d+/) do |token|
x = token.to_i
if haphap.happy(x)
puts "#{x} is happy with rank #{haphap.rank(x)}"
end
end
end
 
M

Michael Ulm

Jacob said:
The period cannot be any larger than 1000. The largest period is
probably quite a bit smaller than this, but this is a upper bound.
Why?

Some definitions, first.

Let's define g(x) as the function that takes a number to it's
successor. For example, g(42) = 4^2 + 2^2 = 20.
--snip--

Actually, it is possible to show that for any three digit number

g(x) < x.

This holds in any base. The proof:

Let the base be b > 1, and the number x be
x = u + b * v + b^2 * w,
with 0 <= u, v, w < b, and w > 0.
Then

x - g(x) = u + b * v + b^2 * w - (u^2 + v^2 + w^2)
= u (1 - u) + v * (b - v) + w * (b^2 - w)
u (1 - u) + b^2 - 1
(b - 1) (2 - b) + b^2 - 1 = 3 * (b - 1) > 0

Regards,

Michael


--
Michael Ulm
R&D Team
ISIS Information Systems Austria
tel: +43 2236 27551-219, fax: +43 2236 21081
e-mail: (e-mail address removed)
Visit our Website: www.isis-papyrus.com
 
P

Phrogz

Sander said:
Just had to test if there was any performance difference, results:

user system total real
inject(0) 20.320000 5.430000 25.750000 ( 34.486938)
inject 20.450000 5.350000 25.800000 ( 30.152165)
inject &:+ 37.860000 5.690000 43.550000 ( 45.670349)
each 11.130000 3.460000 14.590000 ( 15.042142)
C 0.020000 0.000000 0.020000 ( 0.019815)

so inject(0) vs inject doesn't really matter.

Interesting! Thanks for sharing. I'm surprised that #each with += is so
much faster.
 
V

Vance Heron

Ruby said:
The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

http://www.rubyquiz.com/

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone
on Ruby Talk follow the discussion. Please reply to the original quiz message,
if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

by Shane Emmons

Write a program that tells whether a given integer is happy. A happy number is
found using the following process: Take the sum of the squares of its digits,
and continue iterating this process until it yields 1, or produces an infinite
loop.

For example the number 7:

7^2 = 49
4^2 + 9^2 = 97
9^2 + 7^2 = 130
1^2 + 3^2 + 0^2 = 10
1^2 + 0^2 = 1

If a number is not happy than it is obviously unhappy. Now that you have this
program, what is the largest happy number you can find? What is the happiest
number between 1 and 1,000,000. I define the happiest number as the smallest
number that finds the most other happy numbers with it, i.e. 7 found four other
numbers (49, 97, 130, and 10) making it a rank 4 in happiness.

If you find all these examples trivial, write you program so that it will find
happy numbers in other bases such as base 2 or 16. From there you can extend the
program so that it finds happy bases (other than 2 and 4). A happy bases is a
base where all numbers are happy. Good luck.

#! /usr/bin/env ruby

def sum_dig_sq(ival)
sum = 0
while ival > 0 do
ival,dig = ival.divmod(10)
sum += (dig * dig)
end
return sum
end

def happy?(ival)
# sad #s from http://mathworld.wolfram.com/HappyNumber.html
sad = [0, 4, 16, 20, 37, 42, 58, 89, 145]
rank = 0
while true do
return -1 if sad.include?(ival) # check sad 1st - ~87% are sad
ival = sum_dig_sq(ival)
return rank if ival == 1
rank += 1
end
end

if ARGV[0].to_i <= 0
warn "usage: #{$0} <number>\n number must be > 0"
exit
end

processed = []
happiest = []
(0..ARGV[0].to_i).each {|cur_num|
base = cur_num.to_s.split('').sort.join.to_i
processed[base] = happy?(cur_num) unless processed[base]
rank = processed[base]
next if rank < 0

puts "#{cur_num} is happy - rank #{rank}"
happiest[rank] = cur_num unless happiest[rank]
}

happiest.each_with_index do |val, ndx|
puts "Happiest number of rank #{ndx} is #{val}"
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top