余数-我的代码不正确,但是为什么它可以工作?

时间:2022-05-26 20:19:46

Yesterday I completed an exercise (9.5) from the book "Learn to Program" from Chris Pine. It's an integer to Old-school Roman numerals converter.

昨天我完成了克里斯·派恩(Chris Pine)的《学习编程》(Learn to Program)中的一个练习(9.5)。它是一个整数到老式罗马数字转换器。

This is how I did it:

我是这样做的:

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)

When I run the script, it outputs the correct Roman numerals.

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

For example 1200 => MCC

例如1200 => MCC

But, when I woke up today the first thing I thought was, this can't be right! The remainder of 1200 % 1000 is 200 and not 0! But why is the output MCC and not CCCCCCCCCCCC???

但是,当我今天醒来的时候,我首先想到的是,这不可能是对的!剩下的1200 % 1000是200而不是0!但是为什么输出是MCC而不是cccccccccccccc呢?

3 个解决方案

#1


7  

If you trace through the program, it's actually matching the % 100 == 0 twice first, getting CC, and leaving you with 1000. Then it matches % 1000 == 0, leaving CCM. Finally it reverses the string, leaving you with MCC.

如果对程序进行跟踪,它实际上是将% 100 == 0匹配两次,获得CC,并保留1000。然后它匹配% 1000 == 0,离开CCM。最后它反转了字符串,剩下MCC。


Side comment: Interesting approach to the problem as I probably would have used a bunch of >= comparisons building the string in forward order with special cases for the 'subtraction' parts (IV or IX). Although on second read, this solution appears to output IIII and not IV, so the special cases are moot.

评论:有趣的方法问题,我可能会用一堆> =比较远期秩序构建字符串“减法”的特殊情况(IV或第九)。尽管在第二部分阅读,这个解决方案似乎IIII输出而不是第四,特殊情况是悬而未决。

#2


0  

the code calculates the digits in reverse order. i.e.

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

you get a C first, then another C and in the third iteration of the loop, you get the M.

首先是C,然后是C循环的第三次迭代,得到M。

in the end, this line of code:

最后,这一行代码:

roman_number.reverse

reverses CCM to MCC and thus you get the result you actually get.

将CCM反转到MCC,从而得到实际得到的结果。

to better understand what happens, you can change your code as follows:

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

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

becomes:

就变成:

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

do this for every if-block. that way you will see what happens in each step.

对每个if块都这样做。这样你就会看到每一步都发生了什么。

#3


0  

Not an answer, but just for note, here is a method with similar purpose, taken from my personal library:

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

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

#1


7  

If you trace through the program, it's actually matching the % 100 == 0 twice first, getting CC, and leaving you with 1000. Then it matches % 1000 == 0, leaving CCM. Finally it reverses the string, leaving you with MCC.

如果对程序进行跟踪,它实际上是将% 100 == 0匹配两次,获得CC,并保留1000。然后它匹配% 1000 == 0,离开CCM。最后它反转了字符串,剩下MCC。


Side comment: Interesting approach to the problem as I probably would have used a bunch of >= comparisons building the string in forward order with special cases for the 'subtraction' parts (IV or IX). Although on second read, this solution appears to output IIII and not IV, so the special cases are moot.

评论:有趣的方法问题,我可能会用一堆> =比较远期秩序构建字符串“减法”的特殊情况(IV或第九)。尽管在第二部分阅读,这个解决方案似乎IIII输出而不是第四,特殊情况是悬而未决。

#2


0  

the code calculates the digits in reverse order. i.e.

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

you get a C first, then another C and in the third iteration of the loop, you get the M.

首先是C,然后是C循环的第三次迭代,得到M。

in the end, this line of code:

最后,这一行代码:

roman_number.reverse

reverses CCM to MCC and thus you get the result you actually get.

将CCM反转到MCC,从而得到实际得到的结果。

to better understand what happens, you can change your code as follows:

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

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

becomes:

就变成:

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

do this for every if-block. that way you will see what happens in each step.

对每个if块都这样做。这样你就会看到每一步都发生了什么。

#3


0  

Not an answer, but just for note, here is a method with similar purpose, taken from my personal library:

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

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