@virnuls/

Number Names

Python

One of the OCR Coding Challenges

fork
loading
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