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

昨天我完成了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?

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


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

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

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

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

 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