Skip to content

Instantly share code, notes, and snippets.

@prophile
Created February 18, 2012 16:16
import itertools
# Number stringification from
# http://code.activestate.com/recipes/413172-numbers-and-plural-words-as-spoken-english/
_known = {
0: 'zero',
1: 'one',
2: 'two',
3: 'three',
4: 'four',
5: 'five',
6: 'six',
7: 'seven',
8: 'eight',
9: 'nine',
10: 'ten',
11: 'eleven',
12: 'twelve',
13: 'thirteen',
14: 'fourteen',
15: 'fifteen',
16: 'sixteen',
17: 'seventeen',
18: 'eighteen',
19: 'nineteen',
20: 'twenty',
30: 'thirty',
40: 'forty',
50: 'fifty',
60: 'sixty',
70: 'seventy',
80: 'eighty',
90: 'ninety'
}
def _positive_spoken_number(n):
"""Assume n is a positive integer.
>>> _positive_spoken_number(900)
'nine hundred'
>>> _positive_spoken_number(100)
'one hundred'
>>> _positive_spoken_number(100000000000)
'one hundred billion'
>>> _positive_spoken_number(1000000000000)
'one trillion'
>>> _positive_spoken_number(33000000000000)
'thirty-three trillion'
>>> _positive_spoken_number(34954523539)
'thirty-four billion, nine hundred fifty-four million, five hundred twenty-three thousand, five hundred thirty-nine'
"""
#import sys; print >>sys.stderr, n
if n in _known:
return _known[n]
bestguess = str(n)
remainder = 0
if n<=20:
print >>sys.stderr, n, "How did this happen?"
assert 0
elif n < 100:
bestguess= _positive_spoken_number((n//10)*10) + '-' + \
_positive_spoken_number(n%10)
return bestguess
elif n < 1000:
bestguess= _positive_spoken_number(n//100) + ' ' + 'hundred'
remainder = n%100
elif n < 1000000:
bestguess= _positive_spoken_number(n//1000) + ' ' + 'thousand'
remainder = n%1000
elif n < 1000000000:
bestguess= _positive_spoken_number(n//1000000) + ' ' + 'million'
remainder = n%1000000
elif n < 1000000000000:
bestguess= _positive_spoken_number(n//1000000000) + ' ' + 'billion'
remainder = n%1000000000
else:
bestguess= _positive_spoken_number(n//1000000000000)+' '+'trillion'
remainder = n%1000000000000
if remainder:
if remainder >= 100: comma = ','
else: comma = ' and'
return bestguess + comma + ' ' + _positive_spoken_number(remainder)
else:
return bestguess
def spoken_number(n):
"""Return the number as it would be spoken, or just str(n) if unknown.
>>> spoken_number(0)
'zero'
>>> spoken_number(1)
'one'
>>> spoken_number(2)
'two'
>>> spoken_number(-2)
'minus two'
>>> spoken_number(42)
'forty-two'
>>> spoken_number(-1011)
'minus one thousand and eleven'
>>> spoken_number(1111)
'one thousand, one hundred and eleven'
"""
if not isinstance(n, int) and not isinstance(n, long):
return n
if n < 0:
if n in _known: return _known[n]
else: return 'minus ' + _positive_spoken_number(-n)
return _positive_spoken_number(n)
# End of re-used code!
def is_anagram(x, y):
# Test the len first as a minor optimisation
return len(x) == len(y) and sorted(x) == sorted(y)
def number_bonds(sum, minimum=1):
high = (sum + 1) // 2
for a in xrange(minimum, high):
yield (a, sum - a)
def tyson_pairs(max):
symbolic_pair = lambda a, b: '{0} + {1}'.format(a, b)
spoken_pair = lambda a, b: '{0} plus {1}'.format(spoken_number(a),
spoken_number(b))
for (ia, ib) in number_bonds(max):
for (ja, jb) in number_bonds(max, ia + 1):
if (is_anagram(symbolic_pair(ia, ib),
symbolic_pair(ja, jb)) and
is_anagram(spoken_pair(ia, ib),
spoken_pair(ja, jb))):
yield (ia, ib, ja, jb)
for pairs in itertools.chain(*(tyson_pairs(i) for i in xrange(1000))):
print "{0} + {1} = {2} + {3}".format(*pairs)
print "\t{0} plus {1} = {2} plus {3}".format(*map(spoken_number, pairs))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment