Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #89635 > unrolled thread

Is my implementation of happy number OK

Started byCecil Westerhof <Cecil@decebal.nl>
First post2015-04-30 17:59 +0200
Last post2015-05-02 21:23 +0000
Articles 15 — 6 participants

Back to article view | Back to comp.lang.python


Contents

  Is my implementation of happy number OK Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 17:59 +0200
    Re: Is my implementation of happy number OK Jon Ribbens <jon+usenet@unequivocal.co.uk> - 2015-04-30 17:04 +0000
    Re: Is my implementation of happy number OK Ian Kelly <ian.g.kelly@gmail.com> - 2015-04-30 11:37 -0600
      Re: Is my implementation of happy number OK Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 21:05 +0200
    Re: Is my implementation of happy number OK Dave Angel <davea@davea.name> - 2015-04-30 14:53 -0400
      Re: Is my implementation of happy number OK Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 22:35 +0200
        Re: Is my implementation of happy number OK Dave Angel <davea@davea.name> - 2015-04-30 17:31 -0400
      Re: Is my implementation of happy number OK Jon Ribbens <jon+usenet@unequivocal.co.uk> - 2015-04-30 23:31 +0000
        Re: Is my implementation of happy number OK Dave Angel <davea@davea.name> - 2015-04-30 19:52 -0400
          Re: Is my implementation of happy number OK Cecil Westerhof <Cecil@decebal.nl> - 2015-05-01 06:36 +0200
          Re: Is my implementation of happy number OK Jon Ribbens <jon+usenet@unequivocal.co.uk> - 2015-05-01 07:23 +0000
            Re: Is my implementation of happy number OK Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2015-05-01 18:27 +1000
              Re: Is my implementation of happy number OK Ian Kelly <ian.g.kelly@gmail.com> - 2015-05-01 09:03 -0600
              Re: Is my implementation of happy number OK Peter Otten <__peter__@web.de> - 2015-05-01 20:13 +0200
                Re: Is my implementation of happy number OK Jon Ribbens <jon+usenet@unequivocal.co.uk> - 2015-05-02 21:23 +0000

#89635 — Is my implementation of happy number OK

FromCecil Westerhof <Cecil@decebal.nl>
Date2015-04-30 17:59 +0200
SubjectIs my implementation of happy number OK
Message-ID<87oam5vc8k.fsf@Equus.decebal.nl>
I implemented happy_number function:
    _happy_set      = { '1' }
    _unhappy_set    = set()

    def happy_number(n):
        """
        Check if a number is a happy number
        https://en.wikipedia.org/wiki/Happy_number
        """

        def create_current(n):
            current_array = sorted([value for value in str(n) if value != '0'])
            return (current_array, ''.join(current_array))

        global _happy_set
        global _unhappy_set

        current_run         = set()
        current_array, \
            current_string  = create_current(n)
        if current_string in _happy_set:
            return True
        if current_string in _unhappy_set:
            return False
        while True:
            current_run.add(current_string)
            current_array, \
                current_string = create_current(sum([int(value) ** 2
                                                     for value in current_string]))
            if current_string in current_run | _unhappy_set:
                _unhappy_set |= current_run
                return False
            if current_string in _happy_set:
                _happy_set |= current_run
                return True

Besides it need some documentation: is it a good implementation? Or
are there things I should do differently?

To decide for the values from 1 to 1E8 if it is happy or not, takes
280 seconds. Not to bad I think. Also not very good.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [next] | [standalone]


#89645

FromJon Ribbens <jon+usenet@unequivocal.co.uk>
Date2015-04-30 17:04 +0000
Message-ID<slrnmk4o7a.apd.jon+usenet@frosty.unequivocal.co.uk>
In reply to#89635
On 2015-04-30, Cecil Westerhof <Cecil@decebal.nl> wrote:
> Besides it need some documentation: is it a good implementation? Or
> are there things I should do differently?

Here's an alternative implementation which is a bit neater:

    def find_happy(maximum):
	"""Return set of happy numbers between 1 and `maximum`"""
	happy = {1}
	unhappy = set()
	for num in range(maximum + 1):
	    sequence = set()
	    while num not in sequence and num not in unhappy:
		sequence.add(num)
		if num in happy:
		    happy |= sequence
		    break
		nextnum = 0
		while num:
		    num, digit = divmod(num, 10)
		    nextnum += digit * digit
		num = nextnum
	    else:
		unhappy |= sequence
	return happy

[toc] | [prev] | [next] | [standalone]


#89650

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-04-30 11:37 -0600
Message-ID<mailman.137.1430415473.3680.python-list@python.org>
In reply to#89635
On Thu, Apr 30, 2015 at 9:59 AM, Cecil Westerhof <Cecil@decebal.nl> wrote:
> I implemented happy_number function:
>     _happy_set      = { '1' }
>     _unhappy_set    = set()
>
>     def happy_number(n):
>         """
>         Check if a number is a happy number
>         https://en.wikipedia.org/wiki/Happy_number
>         """
>
>         def create_current(n):
>             current_array = sorted([value for value in str(n) if value != '0'])

A generator expression in place of the list comprehension would avoid
creating an intermediate list, which would save memory on extremely
large numbers. Not sure without testing how it would compare on small
numbers. For reference, since size here refers to number of digits,
1E8 would be considered tiny.

Also for large numbers, there might be a smarter data structure to use
than just sorting the digits, which is O(n log n). Simplest would
probably just be a 9-element tuple containing the count of each
non-zero digit, which would be only O(n) to build.

>             return (current_array, ''.join(current_array))

You don't seem to be actually using current_array for anything, so why
not just return the string?

>         global _happy_set
>         global _unhappy_set
>
>         current_run         = set()
>         current_array, \
>             current_string  = create_current(n)

As a stylistic rule, avoid line continuations using \. Prefer using
unclosed parentheses for line continuations, e.g. the above could be
written as:

    (current_array,
     current_string) = create_current(n)

But really, the above is short enough it could just be written on a single line.

Also, I feel like the prefix "current_" is used so much here that it
loses its meaning. All these variable names would be better without
it.

>         if current_string in _happy_set:
>             return True
>         if current_string in _unhappy_set:
>             return False

Instead of two sets, consider using a single _happy_dict with values
True for happy and False for unhappy. Then the above becomes:

    if current_string in _happy_dict:
        return _happy_dict[current_string]

>         while True:
>             current_run.add(current_string)
>             current_array, \
>                 current_string = create_current(sum([int(value) ** 2
>                                                      for value in current_string]))

Since there are only 9 values that get squared, you could precompute
the squares to avoid squaring them over and over again.

>             if current_string in current_run | _unhappy_set:

In case the sets get large it might be better to avoid creating the
union and just do:

    if current_string in current_run or current_string in _unhappy_set:

>                 _unhappy_set |= current_run
>                 return False
>             if current_string in _happy_set:
>                 _happy_set |= current_run
>                 return True

[toc] | [prev] | [next] | [standalone]


#89663

FromCecil Westerhof <Cecil@decebal.nl>
Date2015-04-30 21:05 +0200
Message-ID<87bni5tp0o.fsf@Equus.decebal.nl>
In reply to#89650
Op Thursday 30 Apr 2015 19:37 CEST schreef Ian Kelly:

Most I still have to digest. ;-)

> On Thu, Apr 30, 2015 at 9:59 AM, Cecil Westerhof <Cecil@decebal.nl> wrote:
>> return (current_array, ''.join(current_array))
>
> You don't seem to be actually using current_array for anything, so
> why not just return the string?

My implementation was not finished. I had intended to make it:
        current_array, \
            current_string = create_current(sum([value ** 2
                                                 for value in current_array]))

But it does not make it significantly faster, so yes, I am going to
return only the string.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#89657

FromDave Angel <davea@davea.name>
Date2015-04-30 14:53 -0400
Message-ID<mailman.140.1430420006.3680.python-list@python.org>
In reply to#89635
On 04/30/2015 11:59 AM, Cecil Westerhof wrote:
> I implemented happy_number function:
>      _happy_set      = { '1' }
>      _unhappy_set    = set()
>
>      def happy_number(n):
>          """
>          Check if a number is a happy number
>          https://en.wikipedia.org/wiki/Happy_number
>          """
>
>          def create_current(n):
>              current_array = sorted([value for value in str(n) if value != '0'])
>              return (current_array, ''.join(current_array))
>
>          global _happy_set
>          global _unhappy_set
>
>          current_run         = set()
>          current_array, \
>              current_string  = create_current(n)
>          if current_string in _happy_set:
>              return True
>          if current_string in _unhappy_set:
>              return False
>          while True:
>              current_run.add(current_string)
>              current_array, \
>                  current_string = create_current(sum([int(value) ** 2
>                                                       for value in current_string]))
>              if current_string in current_run | _unhappy_set:
>                  _unhappy_set |= current_run
>                  return False
>              if current_string in _happy_set:
>                  _happy_set |= current_run
>                  return True
>
> Besides it need some documentation: is it a good implementation? Or
> are there things I should do differently?
>
> To decide for the values from 1 to 1E8 if it is happy or not, takes
> 280 seconds. Not to bad I think. Also not very good.
>

First comment, if you're coding a complex implementation like this, take 
the time to do a brute force one as well. Then you can compare the 
results between brute force and your optimized one for all possible 
values, and make sure you haven't introduced any bugs.

My brute force looks like:

#Dave's version, brute force

def davea1(n):
     cache = []
     anum = str(n)
     newnum = 0
     while newnum != 1:
         newnum = sum(int(i)*int(i) for i in anum)
         anum = str(newnum)
         if newnum in cache:
             return False     #not a happy number
         cache.append(newnum)
     return True  #found a happy number

I then tried an optimized one, and my speed is only about 10% faster 
than yours for 1e7 loops.  I show it anyway, since I think it reads a 
little better.  And readability counts much more than a little performance.

  #optimizations:
#   cached happy and unhappy sets
#   sort the digits, and compare only the sorted values, without zeroes
davea_happy = {1}
davea_unhappy = set()

SQUARES = dict((str(i), i*i) for i in xrange(10))

def davea2(n):
     global davea_happy, davea_unhappy
     cache = set()
     newnum = n
     while newnum != 1:
         newnum = int("".join(sorted(str(newnum))))
         if newnum in davea_unhappy or newnum in cache:
             davea_unhappy |= cache
             return False     #not a happy number
         if newnum in davea_happy:
             break
         cache.add(newnum)
         newnum = sum(SQUARES[ch] for ch in str(newnum))
     davea_happy |= cache
     return True  #found a happy number

Finally, I did some testing on Jon Ribben's version.  His was 
substantially faster for smaller sets, and about the same for 10*7.  So 
it's likely it'll be slower than yours and mine for 10**8.  But the real 
reason I didn't like it was it produced a much larger set of 
happy_numbers, which could clog memory a lot sooner.  For 10**7 items, I 
had 3250 happy members, and 19630 unhappy.  And Jon had 1418854 happy 
members.

-- 
DaveA

[toc] | [prev] | [next] | [standalone]


#89672

FromCecil Westerhof <Cecil@decebal.nl>
Date2015-04-30 22:35 +0200
Message-ID<87vbgds6b7.fsf@Equus.decebal.nl>
In reply to#89657
Op Thursday 30 Apr 2015 20:53 CEST schreef Dave Angel:

> On 04/30/2015 11:59 AM, Cecil Westerhof wrote:
>> I implemented happy_number function:
>> _happy_set      = { '1' }
>> _unhappy_set    = set()
>>
>> def happy_number(n):
>> """
>> Check if a number is a happy number
>> https://en.wikipedia.org/wiki/Happy_number
>> """
>>
>> def create_current(n):
>> current_array = sorted([value for value in str(n) if value != '0'])
>> return (current_array, ''.join(current_array))
>>
>> global _happy_set
>> global _unhappy_set
>>
>> current_run         = set()
>> current_array, \
>> current_string  = create_current(n)
>> if current_string in _happy_set:
>> return True
>> if current_string in _unhappy_set:
>> return False
>> while True:
>> current_run.add(current_string)
>> current_array, \
>> current_string = create_current(sum([int(value) ** 2
>> for value in current_string]))
>> if current_string in current_run | _unhappy_set:
>> _unhappy_set |= current_run
>> return False
>> if current_string in _happy_set:
>> _happy_set |= current_run
>> return True
>>
>> Besides it need some documentation: is it a good implementation? Or
>> are there things I should do differently?
>>
>> To decide for the values from 1 to 1E8 if it is happy or not, takes
>> 280 seconds. Not to bad I think. Also not very good.
>>
>
> First comment, if you're coding a complex implementation like this,
> take the time to do a brute force one as well. Then you can compare
> the results between brute force and your optimized one for all
> possible values, and make sure you haven't introduced any bugs.

Not a bad idea.


> My brute force looks like:
>
> #Dave's version, brute force
>
> def davea1(n):
> cache = []
> anum = str(n)
> newnum = 0
> while newnum != 1:
> newnum = sum(int(i)*int(i) for i in anum)
> anum = str(newnum)
> if newnum in cache:
> return False     #not a happy number
> cache.append(newnum)
> return True  #found a happy number
>
> I then tried an optimized one, and my speed is only about 10% faster
> than yours for 1e7 loops. I show it anyway, since I think it reads a
> little better. And readability counts much more than a little
> performance.

Well if it performs better and reads better you surely should show it.


> #optimizations: cached happy and unhappy sets sort the digits, and
> #   compare only the sorted values, without zeroes davea_happy = {1}
> #   davea_unhappy = set()
>
> SQUARES = dict((str(i), i*i) for i in xrange(10))
>
> def davea2(n):
> global davea_happy, davea_unhappy
> cache = set()
> newnum = n
> while newnum != 1:
> newnum = int("".join(sorted(str(newnum))))
> if newnum in davea_unhappy or newnum in cache:
> davea_unhappy |= cache
> return False     #not a happy number
> if newnum in davea_happy:
> break
> cache.add(newnum)
> newnum = sum(SQUARES[ch] for ch in str(newnum))
> davea_happy |= cache
> return True  #found a happy number
>
> Finally, I did some testing on Jon Ribben's version. His was
> substantially faster for smaller sets, and about the same for 10*7.
> So it's likely it'll be slower than yours and mine for 10**8. But
> the real reason I didn't like it was it produced a much larger set
> of happy_numbers, which could clog memory a lot sooner. For 10**7
> items, I had 3250 happy members, and 19630 unhappy. And Jon had
> 1418854 happy members.

My version has 1625 and 9814. I do not understand the difference.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#89676

FromDave Angel <davea@davea.name>
Date2015-04-30 17:31 -0400
Message-ID<mailman.148.1430429500.3680.python-list@python.org>
In reply to#89672
On 04/30/2015 04:35 PM, Cecil Westerhof wrote:
> Op Thursday 30 Apr 2015 20:53 CEST schreef Dave Angel:
>
>>
>> Finally, I did some testing on Jon Ribben's version. His was
>> substantially faster for smaller sets, and about the same for 10*7.
>> So it's likely it'll be slower than yours and mine for 10**8. But
>> the real reason I didn't like it was it produced a much larger set
>> of happy_numbers, which could clog memory a lot sooner. For 10**7
>> items, I had 3250 happy members, and 19630 unhappy. And Jon had
>> 1418854 happy members.
>
> My version has 1625 and 9814. I do not understand the difference.
>

My error.  I had also written a version of the function that stored 
strings instead of ints, and the counts of 3250/19630 was for sets that 
had BOTH.

An exercise for the reader.  Notice that in my brute force algorithm I 
use no global sets.  But I do use an internal list, which is apparently 
unbounded.  So it's feasible to run out of memory.  The challenge is to 
write a similar function that uses no lists, sets, or dicts, just an 
algorithm that detects for an arbitrary sized number whether it's happy 
or not.  (It may not be very quick, but that's yet to be decided.  I'm 
already surprised that the present brute force function  davea1() only 
takes about twice as long as the fancy global caching schemes.

-- 
DaveA

[toc] | [prev] | [next] | [standalone]


#89685

FromJon Ribbens <jon+usenet@unequivocal.co.uk>
Date2015-04-30 23:31 +0000
Message-ID<slrnmk5esv.apd.jon+usenet@frosty.unequivocal.co.uk>
In reply to#89657
On 2015-04-30, Dave Angel <davea@davea.name> wrote:
> Finally, I did some testing on Jon Ribben's version.  His was 
> substantially faster for smaller sets, and about the same for 10*7.  So 
> it's likely it'll be slower than yours and mine for 10**8.

You know what they say about assumptions. Actually, my version is six
times faster for 10**8 (running under Python 3.4).

> But the real reason I didn't like it was it produced a much larger
> set of happy_numbers, which could clog memory a lot sooner.  For
> 10**7 items, I had 3250 happy members, and 19630 unhappy.  And Jon
> had 1418854 happy members.

Er, what? You're complaining that mine is less efficient by not
producing the wrong output?

[toc] | [prev] | [next] | [standalone]


#89686

FromDave Angel <davea@davea.name>
Date2015-04-30 19:52 -0400
Message-ID<mailman.155.1430437953.3680.python-list@python.org>
In reply to#89685
On 04/30/2015 07:31 PM, Jon Ribbens wrote:
> On 2015-04-30, Dave Angel <davea@davea.name> wrote:
>> Finally, I did some testing on Jon Ribben's version.  His was
>> substantially faster for smaller sets, and about the same for 10*7.  So
>> it's likely it'll be slower than yours and mine for 10**8.
>
> You know what they say about assumptions. Actually, my version is six
> times faster for 10**8 (running under Python 3.4).
>
>> But the real reason I didn't like it was it produced a much larger
>> set of happy_numbers, which could clog memory a lot sooner.  For
>> 10**7 items, I had 3250 happy members, and 19630 unhappy.  And Jon
>> had 1418854 happy members.
>
> Er, what? You're complaining that mine is less efficient by not
> producing the wrong output?
>

It's not intended as a criticism;  you solved a different problem.  The 
problem Cecil was solving was to determine if a particular number is 
happy.  The problem you solved was to make a list of all values under a 
particular limit that are happy.

Both produce identical results for the Cecil purpose, and yours is 
faster if one wants all the values.  But if one wants a sampling of 
values, his function will fetch them quickly, and even if you want them 
all, his function will use much less memory.

He keeps only one permutation of each value in the set, for substantial 
savings in space.  For example, he might just keep 28, while you keep 28 
and 82, 208, 280, 802, and 820.


-- 
DaveA

[toc] | [prev] | [next] | [standalone]


#89692

FromCecil Westerhof <Cecil@decebal.nl>
Date2015-05-01 06:36 +0200
Message-ID<87a8xosymm.fsf@Equus.decebal.nl>
In reply to#89686
Op Friday 1 May 2015 01:52 CEST schreef Dave Angel:

> On 04/30/2015 07:31 PM, Jon Ribbens wrote:
>> On 2015-04-30, Dave Angel <davea@davea.name> wrote:
>>> Finally, I did some testing on Jon Ribben's version. His was
>>> substantially faster for smaller sets, and about the same for
>>> 10*7. So it's likely it'll be slower than yours and mine for
>>> 10**8.
>>
>> You know what they say about assumptions. Actually, my version is
>> six times faster for 10**8 (running under Python 3.4).
>>
>>> But the real reason I didn't like it was it produced a much larger
>>> set of happy_numbers, which could clog memory a lot sooner.  For
>>> 10**7 items, I had 3250 happy members, and 19630 unhappy.  And Jon
>>> had 1418854 happy members.
>>
>> Er, what? You're complaining that mine is less efficient by not
>> producing the wrong output?
>>
>
> It's not intended as a criticism; you solved a different problem.
> The problem Cecil was solving was to determine if a particular
> number is happy. The problem you solved was to make a list of all
> values under a particular limit that are happy.

I can also produce a list. I have the following function for that:
    def happy_number_list(n):
        found = []

        for i in range(1, n + 1):
            if happy_number(i):
                found.append(i)
        return found

But the idea is that if you only want to know if a certain number is
happy or not, it is a waist to determine it for every number.

I have to look at the speed increase to determine if it would be
interesting to make a dedicated version for it.
>
> Both produce identical results for the Cecil purpose, and yours is
> faster if one wants all the values. But if one wants a sampling of
> values, his function will fetch them quickly, and even if you want
> them all, his function will use much less memory.
>
> He keeps only one permutation of each value in the set, for
> substantial savings in space. For example, he might just keep 28,
> while you keep 28 and 82, 208, 280, 802, and 820.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#89704

FromJon Ribbens <jon+usenet@unequivocal.co.uk>
Date2015-05-01 07:23 +0000
Message-ID<slrnmk6agn.apd.jon+usenet@frosty.unequivocal.co.uk>
In reply to#89686
On 2015-04-30, Dave Angel <davea@davea.name> wrote:
> On 04/30/2015 07:31 PM, Jon Ribbens wrote:
>> On 2015-04-30, Dave Angel <davea@davea.name> wrote:
>>> But the real reason I didn't like it was it produced a much larger
>>> set of happy_numbers, which could clog memory a lot sooner.  For
>>> 10**7 items, I had 3250 happy members, and 19630 unhappy.  And Jon
>>> had 1418854 happy members.
>>
>> Er, what? You're complaining that mine is less efficient by not
>> producing the wrong output?
>
> It's not intended as a criticism;  you solved a different problem.  The 
> problem Cecil was solving was to determine if a particular number is 
> happy.  The problem you solved was to make a list of all values under a 
> particular limit that are happy.
>
> Both produce identical results for the Cecil purpose, and yours is 
> faster if one wants all the values.  But if one wants a sampling of 
> values, his function will fetch them quickly, and even if you want them 
> all, his function will use much less memory.

I must admit, I'm still not understanding. If you want to know only
whether or not int(1e7) is happy then the calculation takes no
measurable time or memory.

[toc] | [prev] | [next] | [standalone]


#89715

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2015-05-01 18:27 +1000
Message-ID<554338dd$0$13004$c3e8da3$5496439d@news.astraweb.com>
In reply to#89704
On Fri, 1 May 2015 05:23 pm, Jon Ribbens wrote:

> On 2015-04-30, Dave Angel <davea@davea.name> wrote:
>> On 04/30/2015 07:31 PM, Jon Ribbens wrote:
>>> On 2015-04-30, Dave Angel <davea@davea.name> wrote:
>>>> But the real reason I didn't like it was it produced a much larger
>>>> set of happy_numbers, which could clog memory a lot sooner.  For
>>>> 10**7 items, I had 3250 happy members, and 19630 unhappy.  And Jon
>>>> had 1418854 happy members.
>>>
>>> Er, what? You're complaining that mine is less efficient by not
>>> producing the wrong output?
>>
>> It's not intended as a criticism;  you solved a different problem.  The
>> problem Cecil was solving was to determine if a particular number is
>> happy.  The problem you solved was to make a list of all values under a
>> particular limit that are happy.
>>
>> Both produce identical results for the Cecil purpose, and yours is
>> faster if one wants all the values.  But if one wants a sampling of
>> values, his function will fetch them quickly, and even if you want them
>> all, his function will use much less memory.
> 
> I must admit, I'm still not understanding. If you want to know only
> whether or not int(1e7) is happy then the calculation takes no
> measurable time or memory.

Oh, I'm sure somebody would be able to measure it...

Rather than 10**7, how about trying (10**500 + 2). Is it happy?

Using the Python code from Wikipedia:
https://en.wikipedia.org/wiki/Happy_number

SQUARE = dict([(c, int(c)**2) for c in "0123456789"])
def is_happy(n):
  while (n > 1) and (n != 4):
    n = sum(SQUARE[d] for d in str(n))
  return n == 1


I can calculate whether n=10**500 + 2 is happy in less than a millisecond on
my computer. Using your version doesn't even work, as it would require
significantly more than 1000 terrabytes of RAM just to hold the results. I
don't have that much memory.

Your version is a reasonable answer to a different question, but it doesn't
scale to very large inputs.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#89740

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-05-01 09:03 -0600
Message-ID<mailman.18.1430492660.3347.python-list@python.org>
In reply to#89715
On Fri, May 1, 2015 at 2:27 AM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> Rather than 10**7, how about trying (10**500 + 2). Is it happy?
>
> Using the Python code from Wikipedia:
> https://en.wikipedia.org/wiki/Happy_number
>
> SQUARE = dict([(c, int(c)**2) for c in "0123456789"])
> def is_happy(n):
>   while (n > 1) and (n != 4):
>     n = sum(SQUARE[d] for d in str(n))
>   return n == 1
>
>
> I can calculate whether n=10**500 + 2 is happy in less than a millisecond on
> my computer.

Not really the most exciting example, since the following number in
the sequence would be 5. But a random sequence of 500 non-zero digits
doesn't seem to take substantially longer.

[toc] | [prev] | [next] | [standalone]


#89744

FromPeter Otten <__peter__@web.de>
Date2015-05-01 20:13 +0200
Message-ID<mailman.0.1430504017.20872.python-list@python.org>
In reply to#89715
Ian Kelly wrote:

> On Fri, May 1, 2015 at 2:27 AM, Steven D'Aprano
> <steve+comp.lang.python@pearwood.info> wrote:
>> Rather than 10**7, how about trying (10**500 + 2). Is it happy?
>>
>> Using the Python code from Wikipedia:
>> https://en.wikipedia.org/wiki/Happy_number
>>
>> SQUARE = dict([(c, int(c)**2) for c in "0123456789"])
>> def is_happy(n):
>>   while (n > 1) and (n != 4):
>>     n = sum(SQUARE[d] for d in str(n))
>>   return n == 1
>>
>>
>> I can calculate whether n=10**500 + 2 is happy in less than a millisecond
>> on my computer.
> 
> Not really the most exciting example, since the following number in
> the sequence would be 5. But a random sequence of 500 non-zero digits
> doesn't seem to take substantially longer.

I may be missing something, but isn't the '+ 2' in '10**500 + 2' just a 
distraction? 10**500 would bring across nicely what the approach Steven took 
from Wikipeda can do in one iteration where Jon's cannot even find enough 
memory.

Also, with 500 digits and 0 <= d <= 9 

sum(d*d for d in digits) <= 81 * 500

should hold, i. e. on the second iteration the maximum number of digits is 
already down to five in the worst case. By repeating this simple reasoning 
you can tell that all interesting examples must be below 1000 as 
num_digits(3*81) == 3. 

A computer that cannot calculate a lookup table with all 3-digit cases 
should be almost as hard to find as the one needed by Jon ;)

[toc] | [prev] | [next] | [standalone]


#89800

FromJon Ribbens <jon+usenet@unequivocal.co.uk>
Date2015-05-02 21:23 +0000
Message-ID<slrnmkag5c.apd.jon+usenet@frosty.unequivocal.co.uk>
In reply to#89744
On 2015-05-01, Peter Otten <__peter__@web.de> wrote:
> A computer that cannot calculate a lookup table with all 3-digit cases 
> should be almost as hard to find as the one needed by Jon ;)

... or anyone else writing code to return the set of happy numbers.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web