 @virnuls/

Number Names One of the OCR Coding Challenges

Files
• main.py
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
""" This is trickier than it seems at first sight!  If you remember that you can read any number by splitting it into blocks of three digits then it seems quite straightforward until you try to add the 'and's, commas and hyphens in the right places."""

from math import log10 as log
# three names for each digit depending on place value
digits = (("","","ten","zero"),("one","ten", "eleven"),("two","twenty ", "twelve"),("three","thirty ","thirteen"),("four","forty ","fourteen"),("five","fifty ","fifteen"),("six","sixty ","sixteen"),("seven","seventy ","seventeen"),("eight","eighty ","eighteen"),("nine","ninety ","nineteen"))
# suffix for each place value in group of 3 digits
suffix = ("",""," hundred ")
# suffix for each group of three digits
magnitude = (""," thousand"," million"," billion"," trillion"," quadrillion"," quintillion")

def words(number):
# is it a negative number
minus = False
# output will contain the name of the number
output = ""
# is it negative?
if number < 0:
# remember that it was negative...
minus = True
# ...but ignore the minus sign
number = abs(number)
place = 0
# find length of integer part
if number > 0.5:
# the log of the number tells the place value of the
# left-most digit, e.g. int(log(200))=2, 10² = 100s column
place = int(log(number))
# is the number between 10 and 20?
teen = False
text = ""
# correctly set zeros is number isn't a multiple of three digits long
zeros = (place % 3 == 0) * 6 + (place % 3 == 1) * 4
while place >= 0:
# current digit
digit = int((number / 10**place) % 10)
if digit == 0:
# record absence of hundreds, tens or units
zeros += (2**(place % 3))
# is the integer part actually zero?
if int(number) == 0:
text = "zero"
if digit == 1 and (place % 3) == 1:
# if the tens digit is 1, look at the next digit
teen = True
else:
# insert a hyphen where there are tens and units
if (place % 3) == 0 and zeros & 3 == 0 and not teen:
text = text[:-1] + "-"
text += digits[digit][((place % 3) == 1) + teen*2]
if zeros & 4 == 0:
text += suffix[place % 3]
teen = False
# end of a cluster of three digits
if (place % 3) == 0:
if zeros & 4 == 0 and zeros & 3 < 3:
# hundreds and units or tens needs an 'and'
char = text.find("hundred") + 7
text = text[:char] + " and " + text[char+1:]
if place > 0 and zeros < 7:
# add 'thousand', etc., if more than three digits
text += magnitude[int(place/3)]
if output > "" and zeros & 3 < 3 and zeros & 4 == 4 and place == 0:
# thousands, no hundreds but tens or units needs an 'and'
text = " and " + text
elif output > "" and text > "":
# add a comma if the cluster of three digits has a value
output += ", "
output += text
text = ""
zeros = 0
place += -1
# is there anything after the decimal point?
if type(number) == float:
output += " point"
# process decimal part as text to avoid floating point errors
number = str(number)
number = number[number.find(".")+1:]
for digit in number:
output += " " + digits[int(digit)][(digit == "0")*3]
# if it's negative then say so
if minus and number != 0:
output = "minus " + output
# remove any extra spaces than have sneaked in!
print(output.replace("  "," "))

cont = True
print("Enter something other than a number to stop...")
while cont:
try:
number = eval(input("\nGive me a number: "))
words(number)
except:
cont = False