```The writeup is coming later.  For now, here is my solution.

I implemented both European (more logical - BetaMax?) and American
(will dominate - VHS?) numbers.  Though I'd put in 'and's originally,
I also ran with them disabled by removing the comment mark in the
first line of find_for_interval(), so I could compare answers.  First
I did brute force, then tried for something more elegant.

I have to admit that when I read Glenn Parker's solution, I discovered
my 'elegant' version was elegantly incorrect.  It inspired to to fix
things and then refactor out a bit of the duplicated code.

My coding style here is very old-school & c-like. We'll see what I
learn of the Ruby Way during the write-up.

Without 'and's or commas, I get:

english.rb 10_000_000_000

E: 808808885 - eight hundred eight million eight hundred eight
thousand eight hundred eighty-five

A: 8808808885 - eight billion eight hundred eight million eight
hundred eight thousand eight hundred eighty-five

english.rb 10_000_000_000_000

E: 8808808808885 - eight billion eight hundred eight milliard eight
hundred eight million eight hundred eight thousand eight hundred
eighty-five

A: 8808808885 - eight billion eight hundred eight million eight
hundred eight thousand eight hundred eighty-five

If I include the 'and's (still no commas), I get:

english.rb 10_000_000_000

E: 885 - eight hundred and eighty-five

A: 8000000885 - eight billion eight hundred and eighty-five

english.rb 10_000_000_000_000

E: 8000000000885 - eight billion eight hundred and eighty-five

A: 8000000885 - eight billion eight hundred and eighty-five

Code:

#############################################################

=begin
While we normally write numbers using Arabic (or since Quiz #22,
Roman) numerals, numbers can also be written out as English phrases.

For example:

7 == seven (the hard way)
42 == forty-two (a very important number)
2001 == two thousand and one (a space odyssey)
1999 ==  (party like it's) nineteen hundred and ninety-nine

So the quiz is a problem from a Pi Mu Epsilon (US national math club)

"When the integers 1 to 10_000_000_000 are written in the English
language, then sorted as strings, which odd number appears first in
the list?"

- Create Ruby code to translate a number to it's English language form.

- Determine programatically which odd number in 1..10_000_000_000
would sort first if written in English. (Brute force is the obvious
solution, but the computer may have to think about it...)

- Would the answer change for a larger range of values, say 10**30?

- Do French and German Rubyists get a different answer than the
Americans?

=end

module EnglishNumerals

Numbers = {
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'
}

AmExponents = {
3 => 'thousand',
6 => 'million',
9 => 'billion',
12 => 'trillion',
18 => 'quintillion',
21 => 'sexillion',
24 => 'septillion',
27 => 'octillion',
30 => 'nonillion',
33 => 'decillion',
36 => 'undecillion',
39 => 'duodecillion',
42 => 'tredecillion',
45 => 'quattuordecillion',
48 => 'quindecillion',
51 => 'sexdecillion',
54 => 'septendecillion',
57 => 'octodecillion',
60 => 'novemdecillion',
63 => 'vigintillion',
66 => 'unvigintillion',
69 => 'duovigintillion'
}

EurExponents = {
3 => 'thousand',
6 => 'million',
9 => 'milliard',
12 => 'billion',
15 => 'billiard',
18 => 'trillion',
21 => 'trilliard',
30 => 'quintillion',
33 => 'quintilliard',
36 => 'sextillion',
39 => 'sextilliard',
42 => 'septillion',
45 => 'septilliard',
48 => 'octillion',
51 => 'octilliard',
54 => 'noventillion',
57 => 'noventilliard',
60 => 'decillion',
63 => 'decilliard',
66 => 'undecillion',
69 => 'undecilliard'
}

Max_exponent = 69

def self.to_English_base(val, include_and = false)

result = ''

sep = include_and ? ' and ' : ' ';

if val >= 100 then
v1 = val / 100
result << ' ' << Numbers[v1] << ' hundred'
val -= v1 * 100
end

if val >= 20 then
v1 = val / 10
result << sep << Numbers[v1 * 10]
val -= v1 * 10
sep = '-'
end

if val > 0 then
result << sep << Numbers[val]
end

result
end

def self.to_English(val, eu_names = true, include_and = true)
val = val.to_i.abs

return "zero" if val == 0

include_and = false if val <= 100

exp_hash = eu_names ? EurExponents : AmExponents

exp = Max_exponent

result = ''

while val > 0
n = 10 ** exp

if exp == 3 && val >= 1100 && val < 2000 then
v1 = val / 100
val -= v1 * 100
result << to_English_base(v1, false) << ' hundred'
elsif val >= n
v1 = val / n
val -= v1 * n
result << to_English_base(v1, exp == 0 && include_and)
if exp > 0 then
result << ' ' << exp_hash[exp]
end
end

exp -= 3
end

result.strip
end

def self.to_American(val, include_and = true)
to_English(val, false, include_and)
end

def self.lowest_brute(val, eu_names)
lowStr = 'zero'
lowV = 0

(1..val).each { |v|

next if (v & 1) == 0

str = to_English(v, eu_names)
if str < lowStr then
lowV = v
lowStr = str
end
}

[ lowV, lowStr ]
end

def self.find_for_interval(val, exp, eu_names)

include_and = (0 == exp) # && false

lowStr = 'zero'
lowV = 0

if (exp <= 0) then
suffix = ''
elsif eu_names then
suffix = ' ' + EurExponents[exp]
else
suffix = ' ' + AmExponents[exp]
end

(1..val).each { |v|

# Only skip odd numbers if exp == 0
#
next if (0 == exp) && (v & 1) == 0

str = to_English(v, eu_names, include_and) + suffix
if str < lowStr then
lowV = v
lowStr = str
end
}

[ lowV, lowStr ]
end

def self.lowest_elegant(val, eu_names)

# get the first (exp == 0) interval
# smallest with 'and' in 1..999
#
exp = 0
interval_size = val < 1000 ? val : 999;
lowV, lowStr = find_for_interval(interval_size, exp, eu_names)

while (val = val / 1000) > 0

exp += 3

# intermediate interval to tack in front of number so far
#
interval_size = val < 1000 ? val : 999;
vInter, strInter =
find_for_interval(interval_size, exp, eu_names)

str = strInter + ' ' + lowStr
if str < lowStr then
lowStr = str
lowV = lowV + (vInter * 10 ** exp)
end
end

[ lowV, lowStr ]
end
end

# If no argument, then work in interactive mode
#
if !ARGV[0] || ARGV[0].to_i == 0 then

\$<.each_line { |line|
puts EnglishNumerals.to_English(line.chomp)
puts EnglishNumerals.to_American(line.chomp)
}

else
val = ARGV[0].to_i

# Positive argument, try something clever...
#
if val > 0
vE, strE = EnglishNumerals.lowest_elegant(val, true)
vA, strA = EnglishNumerals.lowest_elegant(val, false)

# Negative argument, do a brute force solution
#
else
vE, strE = EnglishNumerals.lowest_brute(val.abs, true)
vA, strA = EnglishNumerals.lowest_brute(val.abs, false)
end

puts "E: #{vE} - #{strE}"
puts "A: #{vA} - #{strA}"
end

#############################################################

```