Need help on a program

  • Thread starter Christopher Latif
  • Start date
C

Christopher Latif

Stuck on this exercise from a book:
Old-school Roman numerals. In the early days of Roman numerals,
the Romans didn’t bother with any of this new-fangled subtraction
“IX†nonsense. No sir, it was straight addition, biggest to littlest—
so 9 was written “VIIII,†and so on. Write a method that, when
passed an integer between 1 and 3000 (or so), returns a string
containing the proper old-school Roman numeral. In other words,
old_roman_numeral 4 should return 'IIII'. Make sure to test
your method on a bunch of different numbers.
For reference, these are the values of the letters used:
I =1 V =5 X = 10 L = 50
C = 100 D = 500 M = 1000

Suggestions on a soloution?
 
E

Edwin Fine

Suggestions on a soloution?
There's one in the Ruby Cookbook, by O'Reilly. I am sure there would be
some on Google, too. I even think I recall a RubyQuiz on this topic.
 
J

Jan Svitok

Stuck on this exercise from a book:
Old-school Roman numerals. In the early days of Roman numerals,
the Romans didn't bother with any of this new-fangled subtraction
"IX" nonsense. No sir, it was straight addition, biggest to littlest=97
so 9 was written "VIIII," and so on. Write a method that, when
passed an integer between 1 and 3000 (or so), returns a string
containing the proper old-school Roman numeral. In other words,
old_roman_numeral 4 should return 'IIII'. Make sure to test
your method on a bunch of different numbers.
For reference, these are the values of the letters used:
I =3D1 V =3D5 X =3D 10 L =3D 50
C =3D 100 D =3D 500 M =3D 1000

Suggestions on a soloution?

1. skeleton (I'll use test/unit, as it's easier to check the results)

require 'test/unit'

def to_roman(int)
# here comes the code
end

class TestToRoman < Test::Unit::TestCase
# check the base digits
def test_roman_digits
assert_equal 'I', to_roman(1)
assert_equal 'V', to_roman(5)
assert_equal 'X', to_roman(10)
assert_equal 'L', to_roman(50)
assert_equal 'C', to_roman(100)
assert_equal 'D', to_roman(500)
assert_equal 'M', to_roman(1000)
end

def test_roman_more
assert_equal 'I', to_roman(1)
assert_equal 'II', to_roman(2)
assert_equal 'III', to_roman(3)
assert_equal 'IIII', to_roman(4)

assert_equal 'VI', to_roman(6)
assert_equal 'VII', to_roman(7)
assert_equal 'VIII', to_roman(8)
assert_equal 'VIIII', to_roman(9)

assert_equal 'MDCCCCLXXXVIIII', to_roman(1989)
end
end

2. to the actual solution:
(you'll be creating the number left-to-right)

*find largest digit less than the number. subtract its value from the
number, add the digit to the result*. repeat until the digit is larger
than the remainder. if there's anything left, choose the next digit.

in fact, the text between the stars is the simplest/most generic
algorithm. the following things are just an optimisation.

The actual ruby code I'll leave to you. First do anything that works
(use the test above to check, and add your own ones), no matter how
ugly it is. Then post your code, and somebody (be it me or anybody
else) will suggest you improvements.

3. a bit of rubyism:

instead of
def to_roman(int)
...
end

and calling as to_roman(123) you can extend the integers themselves:

class Integer
def to_roman
# use self insted of int parameter
end
end

and call as 123.to_roman - it's nicer.
 
W

William James

Christopher said:
Stuck on this exercise from a book:
Old-school Roman numerals. In the early days of Roman numerals,
the Romans didn't bother with any of this new-fangled subtraction
"IX" nonsense. No sir, it was straight addition, biggest to littlest-
so 9 was written "VIIII," and so on. Write a method that, when
passed an integer between 1 and 3000 (or so), returns a string
containing the proper old-school Roman numeral. In other words,
old_roman_numeral 4 should return 'IIII'. Make sure to test
your method on a bunch of different numbers.
For reference, these are the values of the letters used:
I =1 V =5 X = 10 L = 50
C = 100 D = 500 M = 1000

Suggestions on a soloution?

class Integer
def to_roman
"I =1 V =5 X = 10 L = 50
C = 100 D = 500 M = 1000".
scan( / ([A-Z]) \s *= \s* (\d+) /x ).
map{|letter,val| [ letter, val.to_i ] }.
sort_by{|a| -a.last}.
inject( [ "", self ] ){|roman, pair|
[ roman.first + pair.first * (roman.last / pair.last),
roman.last % pair.last ] }.
first
end
end
 
H

Hung Dao

#!/usr/bin/env ruby
@data = [
[
"M" , 1000],
["CM" , 900],
["D" , 500],
"CD" , 400],
[
["C" , 100],
[
"XC" , 90],
"L" , 50],
[
"XL" , 40],
[
["X" , 10],
["IX" , 9],
"V" , 5],
[
[
"IV" , 4],
"I" , 1]
[
]
@roman = %r{^[CDILMVX]*$}
@arabic = %r{^[0-9]*$}
def to_roman(num)
""
reply =
for key, value in @data
count, num = num.divmod(value)
reply << (key * count)
end
reply
end
def
to_arabic(rom)
reply = 0
for key, value in @data
while rom.index(key) == 0
reply += value
rom.slice!(key)
end
end
reply
end
$stdin.each do |line|
case line
when @roman
puts to_arabic(line)
when @arabic
puts to_roman(line.to_i)
end
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top