# Putting numbers into words

I have some embarrassingly long code which puts into words any number up into the trillions. As a newbie, and understanding that shorter, non-repetitive code is best, I am looking for suggestions on how to reduce this code to a respectable quantity. I realize that there is a lot of repetition in it. However, depending on the number being evaluated, the math looks a little different with each rep, so I am not sure if I can reduce that. I have tried rewriting it solely as an if/else (without the recursion) but it quickly becomes just as bad if not worse.

class :: Fixnum

def in_words(number)

if number < 0  # No negative numbers.
return 'Please enter a number that isn\'t negative.'
end

if number == 0
return 'zero'
end

numString = ''  # This is the string we will return.

onesPlace = ['one',     'two',       'three',    'four',     'five',
'six',     'seven',     'eight',    'nine']
tensPlace = ['ten',     'twenty',    'thirty',   'forty',    'fifty',
'sixty',   'seventy',   'eighty',   'ninety']
teenagers = ['eleven',  'twelve',    'thirteen', 'fourteen', 'fifteen',
'sixteen', 'seventeen', 'eighteen', 'nineteen']

#-----------------------------------------trillions

left = number
write = left/1000000000000
left = left - (write*1000000000000)

if number > 999999999999

if write < 10 #1,00 - 9,000
millions  = onesPlace[write - 1]
numString = numString + millions + ' trillion'
end

if (write > 9) && (write < 20) #10,000 - 19,000
if write == 10
millions = tensPlace[write - 10]
numString = numString + millions + ' trillion'
else
millions = teenagers[write - 11] #11 because the length of teenagers is only 9 so 15-11 = 4 and 'thirteen' is in
numString = numString + millions + ' trillion'
end
end

if (write > 19) && (write < 1000) #here i have to use recursion to get the first two/three digets --> 19,000,000 - 999,000,000
millions = in_words(write)
numString = numString + millions + ' trillion'
end

if left > 0
numString = numString + ' '
end

#-----------------------------------------billions
#left = number
write = left/1000000000
left = left - (write*1000000000)

if number > 999999999

if write < 10 #1,00 - 9,000
millions  = onesPlace[write - 1]
numString = numString + millions + ' billion'
end

if (write > 9) && (write < 20) #10,000 - 19,000
if write == 10
millions = tensPlace[write - 10]
numString = numString + millions + ' billion'
else
millions = teenagers[write - 11] #11 because the length of teenagers is only 9 so 15-11 = 4 and 'thirteen' is in
numString = numString + millions + ' billion'
end
end

if (write > 19) && (write < 1000) #here i have to use recursion to get the first two/three digets --> 19,000,000 - 999,000,000
millions = in_words(write)
numString = numString + millions + ' billion'
end

if left > 0
numString = numString + ' '
end

# ----------------------------------------millions
write = left/1000000
left = left - (write*1000000)

if number > 999999

if write < 10 #1,00 - 9,000
millions  = onesPlace[write - 1]
numString = numString + millions + ' million'
end

if (write > 9) && (write < 20) #10,000 - 19,000
if write == 10
millions = tensPlace[write - 10]
numString = numString + millions + ' million'
else
millions = teenagers[write - 11] #11 because the length of teenagers is only 9 so 15-11 = 4 and 'thirteen' is in
numString = numString + millions + ' million'
end
end

if (write > 19) && (write < 1000) #here i have to use recursion to get the first two/three digets --> 19,000,000 - 999,000,000
millions = in_words(write)
numString = numString + millions + ' million'
end

if left > 0
numString = numString + ' '
end

#-----------------------------------------thousands
write = left/1000
left = left - (write*1000)

if number > 999

if write < 10 #1,00 - 9,000
thousands  = onesPlace[write - 1]
numString = numString + thousands + ' thousand'
end

if (write > 9) && (write < 20) #10,000 - 19,000
if write == 10
thousands = tensPlace[write - 10]
numString = numString + thousands + ' thousand'
else
thousands = teenagers[write - 11] #11 because the length of teenagers is only 9 so 15-11 = 4 and 'thirteen' is in
numString = numString + thousands + ' thousand'
end
end

if (write > 19) && (write < 1000) #here i have to use recursion to get the first two/three digits --> 19,000 - 999,000
thousands = in_words(write)
numString = numString + thousands + ' thousand'
end

if left > 0
numString = numString + ' '
end
end
end
end
end
# ------------- hundreds
write = left/100
left  = left - (write*100)

if write > 0
hundreds  = in_words(write)
numString = numString + hundreds + ' hundred'

if left > 0
numString = numString + ' '
end
end

# ---------------- tens
write = left/10    #stop here and return
#numString = numString +
left  = left - write*10

if write > 0
if ((write == 1) and (left > 0))
numString = numString + teenagers[left-1]
left = 0
else
numString = numString + tensPlace[write-1]
end

if left > 0
numString = numString + '-'
end
end

write = left
left  = 0

if write > 0
numString = numString + onesPlace[write-1]
end

numString
end

end#class

puts 95202824653012.in_words(95202824653012)


Another problem I have with it is that it is a method added to the Fixnum class and I would like to be able to call it directly on self without an argument, for example 3457278.in_words instead of 3457278.in_words(3457278). The problem seems to be that the recursion needs an argument when it is called, and therefore the method needs one. Or is there a way around that?

• Related question Commented Mar 26, 2015 at 0:21

Rather than rewrite your whole solution, I'll point out more idiomatic ways to do this stuff in Ruby.

## Recursion

You don't need an argument to do recursion, self is enough.

class ::Fixnum
def in_words
# ...
millions = write.in_words
# ...
end
end


## String Arrays

%w{} is handy for making arrays containing one-word strings

ones_place = %{one two three four five six seven eight nine}


## Long Numbers

_ can be used like a comma (or period, if you're European) in long numbers.

billion = 1_000_000_000


For powers of 10, you can also use exponentiation

trillion = 10 ** 12


## Modulus

% gets the remainder of a number after dividing.

write = left / 10 ** 9
left = left % 10 ** 9


## Assignment Shortcut

x = x <op> y can be written as x <op>= y where <op> is any operator.

numString += ' '
left %= 10 ** 9


## Loops

Once you incorporate all of those, you should be able to see how that huge nested if can be turned into a tiny

[12, 9, 6, 3].each do |power|
break if self < 10 ** power
# ...
end

• awesome suggestions! in addition, because of the specific answer to the recursion I will mark this as the answer. I will use your suggestions...cant wait to see how much i can shorten this with them!
– HolyMoly
Commented Mar 24, 2015 at 22:38
• Actually, Code Review (where this got migrated) is not about rewriting code. This advice is fine. It is, however, the place for working code that needs to be refactored. Commented Mar 25, 2015 at 20:51