2

昨天我完成了 Chris Pine 的“Learn to Program”一书中的练习(9.5)。它是一个整数到老式罗马数字的转换器。

我是这样做的:

def old_roman_numeral number
    roman_number = ""
    while number != 0
        if number % 1000 == 0
            number -= 1000
            roman_number += "M"
            next
        elsif number % 500 == 0
            number -= 500
            roman_number += "D"
            next
        elsif number % 100 == 0
            number -= 100
            roman_number += "C"
            next
        elsif number % 50 == 0
            number -= 50
            roman_number += "L"
            next
        elsif number % 10 == 0
            number -= 10
            roman_number += "X"
            next
        elsif number % 5 == 0
            number -= 5
            roman_number += "V"
            next
        else
            number -= 1
            roman_number += "I"
        end
    end
    roman_number.reverse
end

puts "Please enter any number and I convert it to"
puts "Old-school Roman numerals."
puts
num = gets.chomp.to_i
puts "Your number #{num} converted to Old-school Roman is:"
puts (old_roman_numeral num)

当我运行脚本时,它会输出正确的罗马数字。

例如 1200 => MCC

但是,当我今天醒来时,我的第一反应是,这不可能!1200 % 1000 的余数是 200 而不是 0!但是为什么输出的是MCC而不是CCCCCCCCCCCC???

4

3 回答 3

7

如果您跟踪该程序,它实际上% 100 == 0首先匹配两次,得到CC,然后给您 1000。然后它匹配% 1000 == 0,离开CCM。最后它反转字符串,留下MCC.


旁注:解决这个问题的方法很有趣,因为我可能会使用一堆>=比较来按正序构建字符串,并带有“减法”部分(IVIX)的特殊情况。虽然在第二次阅读时,这个解决方案似乎输出IIII而不是IV,所以特殊情况没有实际意义。

于 2013-07-01T08:10:12.963 回答
0

该代码以相反的顺序计算数字。IE

你得到C第一个,然后是另一个C,在循环的第三次迭代中,你得到M.

最后,这行代码:

roman_number.reverse

反转CCMMCC因此你得到你实际得到的结果。

为了更好地理解发生了什么,您可以按如下方式更改代码:

    if number % 1000 == 0
        number -= 1000
        roman_number += "M"
        next

变成:

    if number % 1000 == 0
        number -= 1000
        roman_number += "M"
        puts "number " + number.to_s
        puts "roman_number " + roman_number
        next

对每个 if 块执行此操作。这样你就会看到每一步会发生什么。

于 2013-07-01T08:20:50.587 回答
0

不是答案,只是为了说明,这是一个具有类似目的的方法,取自我的个人图书馆:

class Numeric
  RomanNumerals = {
    1000 => "m", 900 => "cm", 500 => "d", 400 => "cd",
    100 => "c", 90 => "xc", 50 => "l", 40 => "xl",
    10 => "x", 9 => "ix", 5 => "v", 4 => "iv", 1 => "i"
  }

  def roman
    return to_s unless 0 < self and self < 4000 # Cannot be romanized
    s, r = "", self
    RomanNumerals.each{|d, c| q, r = r.divmod(d); s.concat(c*q)}
    s
  end
end
于 2013-07-01T11:27:26.123 回答