剩余 - 我的代码不正确,但为什么它有效?

时间:2013-07-01 08:06:03

标签: ruby

昨天我完成了Chris Pine的“学习计划”一书中的练习(9.5)。 它是Old-school Roman数字转换器的整数。

我就这样做了:

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

3 个答案:

答案 0 :(得分:7)

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


副评论:这个问题的有趣方法,因为我可能会使用一堆>=比较来按正向顺序构建字符串,其中包含“减法”部分的特殊情况(IV或{{ 1}})。虽然在第二次阅读时,此解决方案似乎输出IX而不是IIII,因此特殊情况没有实际意义。

答案 1 :(得分:0)

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

首先获得C,然后获得另一个C,并在循环的第三次迭代中获得M

最后,这行代码:

roman_number.reverse

CCM反转为MCC,从而获得实际获得的结果。

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

    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块执行此操作。这样你就会看到每一步都会发生什么。

答案 2 :(得分: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