# Happy Numbers (#93) - happy bases

**URL:** <https://www.ruby-forum.com/t/happy-numbers-93-happy-bases/67762>\
**Category:** Ruby\
**Created:** [September 6, 2006, 5:02pm UTC](https://www.ruby-forum.com/t/happy-numbers-93-happy-bases/67762 "2006-09-06T17:02:15Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [September 6, 2006, 5:02pm UTC](https://www.ruby-forum.com/t/happy-numbers-93-happy-bases/67762/1 "2006-09-06T17:02:15Z")

</div>

Here’s my solution to find happy bases - note that I don’t find any  
happy bases (aside from 2 and 4) before I run out of memory, somewhere  
near base 1700. It wouldn’t surprise me if no other happy bases  
exist.

The program checks up to 2\*(base-1)\*(base-1) for numbers that fall  
into an infinite loop (that is not ‘1’ forever) when applying the  
digit-square-sum function. This is all that’s needed, as it can  
easily be shown that any number will eventually get less than that.

There’s almost certainly some stuff I could do to be more parsimonious  
with memory, chief among them finding a copy of narray that has the  
.mod! method. (I may revisit this and use a combination of div!, mul!  
and sbt! to cut down on temporary arrays) However, this program as it  
stands very quickly checks much farther out than I would have thought  
necessary if there really were other happy bases out there to be  
found.

#!/usr/bin/env ruby  
require ‘narray’

def dodigsum(base, initial)  
tmp = initial / (base \*\* NArray.to\_na([[0],[1],[2]]))

# I would use mod!, but my copy of narray doesn’t have mod!

tmp = tmp % base  
tmp.mul!(tmp)  
initial.fill!(0).add!(tmp.sum(1))  
end

def checkbase(base = 10)  
base = base.to\_i  
checklimit = 2\*(base-1)\*(base-1)  
check = NArray.int(checklimit + 1).indgen!  
check\_initial = check.dup

while true do  
dodigsum(base,check)  
if check.eq(check\_initial).count\_true \> 2  
#Gobs of debugging info  
# lp = check.mul!(check.eq(check\_initial)).mask(check.ge(2)).min  
# puts “#{base} has a loop on #{lp}”  
break  
end  
if check.le(1).count\_true \> checklimit  
puts “#{base} is a happy base”  
break  
end  
end  
end

2.upto(3000) { |b|  
begin  
checkbase(b)  
rescue Interrupt  
puts “Checking #{b}”  
checkbase(b)  
rescue Error =\> e  
puts “Bailing on #{b}”  
raise e  
end  
}

**END**

---

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [September 6, 2006, 9:08pm UTC](https://www.ruby-forum.com/t/happy-numbers-93-happy-bases/67762/2 "2006-09-06T21:08:51Z")

</div>

And here’s my narray-based solution to find the happiest number under  
1\_000\_000 - it’s not the shortest solution I’ve seen, but it’s pretty  
fast. It eliminates numbers that end up in loops by setting all  
looping numbers to 0.

#!/usr/bin/env ruby  
require ‘narray’

def dodigsum(initial, base)  
ndigits = (Math.log(initial.max)/Math.log(base)).ceil  
tmp = initial / (base \*\* NArray.to\_na((0…ndigits).map{|x|[x]}))  
tmp = tmp % base  
tmp.mul!(tmp)  
initial.fill!(0).add!(tmp.sum(1))  
end

limit = ARGV[0] || 1\_000\_000  
base = ARGV[1] || 10

limit = limit.to\_i  
base = base.to\_i

check = NArray.int(limit + 1).indgen!  
check\_initial = check.dup  
check\_initial[1] = 0  
dodigsum(check, base)  
checkp = check.dup

onemask = check.eq(1)

# onemask now contains the location of “0 order” happy numbers

order = 0  
found\_ex = nil  
while (check.ge(2).count\_true \> 0) do  
check.mul!(check.ne(check\_initial))  
check = check[checkp]  
newmask = check.eq(1)  
order = order + 1  
if (not newmask == onemask)  
found\_ex = [newmask.gt(onemask).where.min, order]  
end  
onemask = newmask  
end  
puts “Happiest is #{found\_ex[0]}, with happiness order #{found\_ex[1]}”  
**END**

---

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [September 7, 2006, 9:28am UTC](https://www.ruby-forum.com/t/happy-numbers-93-happy-bases/67762/3 "2006-09-07T09:28:07Z")

</div>

Daniel M. wrote:

> Daniel M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:
> 
> > Here’s my solution to find happy bases - note that I don’t find any  
> > happy bases (aside from 2 and 4) before I run out of memory, somewhere  
> > near base 1700. It wouldn’t surprise me if no other happy bases  
> > exist.

I used the attached program to check for happy bases.

$ time ruby hapnr2.rb 10000  
2  
4

real 1m7.279s  
user 1m7.261s  
sys 0m0.013s

So, there are no more happy bases up to 10000.

Regards,

Michael

–  
Michael U.  
R&D Team  
ISIS Information Systems Austria  
tel: +43 2236 27551-219, fax: +43 2236 21081  
e-mail: removed\_email\_address@domain.invalid  
Visit our Website: [www.isis-papyrus.com](http://www.isis-papyrus.com)

---

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [September 6, 2006, 8:14pm UTC](https://www.ruby-forum.com/t/happy-numbers-93-happy-bases/67762/4 "2006-09-06T20:14:46Z")

</div>

Daniel M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> Here’s my solution to find happy bases - note that I don’t find any  
> happy bases (aside from 2 and 4) before I run out of memory, somewhere  
> near base 1700. It wouldn’t surprise me if no other happy bases  
> exist.

And here’s a faster version, and I also corrected the “Error” to  
“Exception” mistake I’d made in my earlier version. This version  
makes it through bases 2 - 100 in the blink of an eye, but really  
starts to slow down around base 700.

I haven’t had a chance to run this one as far as it can go without  
running out of memory; maybe later today.

Still haven’t found any other happy bases…

#! /usr/bin/env ruby  
require ‘narray’

def dodigsum(initial, base)  
tmp = initial / (base \*\* NArray.to\_na([[0],[1],[2]]))

# I would use mod!, but my copy of narray doesn’t have mod!

tmp = tmp % base  
tmp.mul!(tmp)  
initial.fill!(0).add!(tmp.sum(1))  
end

def checkbase(base = 10)

# As shown on the list, you’re guaranteed that eventually every

# number will be two digits or less, and once there the highest

# you’ll ever get again is…

checklimit = 2\*(base-1)\*(base-1)  
check = NArray.int(checklimit + 1).indgen!  
check\_initial = check.dup  
dodigsum(check,base)  
checkp = check.dup

while true do  
if check.eq(check\_initial).count\_true \> 2  
#lp = check.mul!(check.eq(check\_initial)).mask(check.ge(2)).min  
#puts “#{base} has a loop on #{lp}”  
print (base % 100 \> 0 ? “.” : “x”)  
break  
end  
if check.le(1).count\_true \> checklimit  
puts “#{base} is a happy base”  
break  
end  
check[0] = check[checkp]  
end  
end

2.upto(3000) { |b|  
begin  
checkbase(b)  
GC.start if (b \> 300 and b % 5 == 0)  
sleep(1) if (b % 100 == 0)  
rescue Interrupt  
puts “Checking #{b}”  
checkbase(b)  
rescue Exception =\> e  
puts “Bailing on #{b}”  
raise e  
end  
}

**END**
