Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #89635 > unrolled thread
| Started by | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| First post | 2015-04-30 17:59 +0200 |
| Last post | 2015-05-02 21:23 +0000 |
| Articles | 15 — 6 participants |
Back to article view | Back to comp.lang.python
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
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2015-04-30 17:59 +0200 |
| Subject | Is 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]
| From | Jon Ribbens <jon+usenet@unequivocal.co.uk> |
|---|---|
| Date | 2015-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]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2015-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2015-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]
| From | Dave Angel <davea@davea.name> |
|---|---|
| Date | 2015-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2015-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]
| From | Dave Angel <davea@davea.name> |
|---|---|
| Date | 2015-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]
| From | Jon Ribbens <jon+usenet@unequivocal.co.uk> |
|---|---|
| Date | 2015-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]
| From | Dave Angel <davea@davea.name> |
|---|---|
| Date | 2015-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]
| From | Cecil Westerhof <Cecil@decebal.nl> |
|---|---|
| Date | 2015-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]
| From | Jon Ribbens <jon+usenet@unequivocal.co.uk> |
|---|---|
| Date | 2015-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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2015-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]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2015-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]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2015-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]
| From | Jon Ribbens <jon+usenet@unequivocal.co.uk> |
|---|---|
| Date | 2015-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