简体   繁体   English

为什么.to_s会破坏此代码?

[英]Why does .to_s break this code?

I'm working on a Codewars Ruby problem, and don't understand the error I'm seeing. 我正在处理Codewars Ruby问题,但无法理解我看到的错误。 Here are the instructions: 以下是说明:

Coding decimal numbers with factorials is a way of writing out numbers in a base system that depends on factorials, rather than powers of numbers. 用阶乘编码小数是一种在基本系统中写数字的方法,该系统依赖于阶乘而不是数字的幂。 In this system, the last digit is always 0 and is in base 0!. 在此系统中,最后一位数字始终为0,以0为底。 The digit before that is either 0 or 1 and is in base 1!. 之前的数字是0或1,并且以1为底! The digit before that is either 0, 1, or 2 and is in base 2!. 之前的数字是0、1或2,并且以2为底! More generally, the nth-to-last digit in always 0, 1, 2, ..., or n and is in base n!. 更一般而言,第n个倒数始终为0、1、2,...或n,并以n!为基数。

Example : decimal number 463 is coded as "341010" 示例:十进制数字463编码为“ 341010”

because 463 (base 10) = 3×5! 因为463(基数10)= 3×5! + 4×4! + 4×4! + 1×3! + 1×3! + 0×2! + 0×2! + 1×1! + 1×1! + 0×0! + 0×0!

If we are limited to digits 0...9 the biggest number we can code is 10! 如果我们限于数字0 ... 9,则我们可以编码的最大数字为10! - 1. -1。

So we extend 0..9 with letters A to Z. With these 36 digits we can code up to 36! 因此,我们用字母A到Z扩展0..9。使用这36个数字,我们最多可以编码36个! − 1 = 37199332678990121746799944815083519999999910 (base 10) − 1 = 37199332678990121746799944815083519999999910(以10为底)

We code two functions, the first one will code a decimal number and return a string with the factorial representation : "dec2FactString(nb)" 我们编写了两个函数,第一个将编码一个十进制数,并返回一个以阶乘表示的字符串:“ dec2FactString(nb)”

the second one will decode a string with a factorial representation and produce the decimal representation : "factString2Dec(str)". 第二个将解码具有阶乘表示形式的字符串并产生十进制表示形式:“ factString2Dec(str)”。

Given numbers will be positive. 给定的数字将为正。

Note 注意

You can hope tests with Big Integers in Clojure, Python, Ruby, Haskel but not with Java and others where the number "nb" in "dec2FactString(nb)" is at most a long. 您可以希望使用Clojure,Python,Ruby,Haskel中的Big Integers进行测试,而不希望使用Java和“ dec2FactString(nb)”中最多为“ nb”的Java等测试。

Ref: http://en.wikipedia.org/wiki/Factorial_number_system 参考: http : //en.wikipedia.org/wiki/Factorial_number_system

def dec2FactString(nb)
  if nb <= 0 then
    num = 1
  else
    num = (nb * dec2FactString(nb - 1))
  end
  return num
end

Note that this method is only the first half of the problem. 请注意,此方法只是问题的前半部分。 This code appears to work inasmuch as it returns the correct factorial, as a Fixnum when using this test: 这段代码似乎可以正常工作,因为它在使用此测试时返回正确的阶乘(如Fixnum):

Test.assert_equals(dec2FactString(4), "24") 

Since the instructions ask for a string, I'd normally think that just adding ".to_s" to the num variable would take care of that, but instead I'm seeing a consistent "String can't be coerced into Fixnum (TypeError)" error message. 由于指令要求输入字符串,因此我通常认为仅将“ .to_s”添加到num变量就可以解决问题,但是相反,我看到一致的“ String不能强制到Fixnum(TypeError)中“ 错误信息。 I've tried pushing the output to an array and printing from there, but saw the same error. 我试过将输出推到数组并从那里打印,但是看到了同样的错误。

I read up on Fixnum a little, and I understand the error in terms of adding a Fixnum to a string won't work, but I don't think I'm doing that in this case - I just want to convert the Fixnum output into a string. 我稍微读了一下Fixnum,并且我了解了将Fixnum添加到字符串方面的错误是行不通的,但是在这种情况下,我不认为我正在这样做-我只想转换Fixnum输出变成一个字符串。 Am I missing something? 我想念什么吗?

Observe - this code breaks and produces the error below it: 观察-此代码中断并在其下产生错误:

def dec2FactString(nb)
  if nb <= 0 then
    num = 1
  else
    num = (nb * dec2FactString(nb - 1))
  end
  return num.to_s
end

Example from description
 `*': String can't be coerced into Fixnum (TypeError)
    from `dec2FactString'
    from  `dec2FactString'
    from  `dec2FactString'
    from  `dec2FactString'
    from  `block in 
'
    from  `block in describe'
    from  `measure'
    from  `describe'
    from  `
'

You're calling this function recursively. 您正在递归调用此函数。 If you calculated the factorial of 1 and left to_s in there, it'd be fine since you're not reusing the variable. 如果您计算的阶乘为1并在其中保留to_s ,那将是很好的,因为您不会重复使用该变量。

However, if you do place to_s in there, what would you expect the result of num = (nb * dec2FactString(nb - 1)) to be? 但是,如果您确实在其中放置了to_s ,那么您希望num = (nb * dec2FactString(nb - 1))的结果是什么? dec2FactString would be returning a str instead of a Fixnum , and you can't/shouldn't be able to do multiplication between a number and a string. dec2FactString将返回str而不是Fixnum ,并且您不能/不应该在数字和字符串之间进行乘法。

What you could do is split the responsibilities of stringification and calculation by creating two methods - one that delegates to the recursive function, and one that coerces its result into a string. 您可以做的是通过创建两种方法来划分字符串化和计算的职责:一种方法委托给递归函数,另一种方法将其结果强制为字符串。

def dec2FactString(nb)
    return fact(nb).to_s
end

def fact(nb)
    if nb <= 0 then
        1
    else
        nb * fact(nb - 1)
    end
end

Firstly, Factorial is only defined on non-negative numbers and so your first test is incorrect (if nb <= 0). 首先,阶乘仅在非负数上定义,因此您的第一个测试是错误的(如果nb <= 0)。 The recursion should stop when the number is 0 and should return 1 at that point. 当数字为0时,递归应停止,并应在此时返回1。

Because your recursion returns a string and not a number, you cannot multiply the string by a Fixnum in the next round of recursion. 因为递归返回的是字符串而不是数字,所以在下一轮递归中不能将字符串乘以Fixnum。 Your recursion can be expanded via the substitution method to the following. 可以通过替代方法将递归扩展为以下内容。

dec2FactString(5)
5 * dec2FactString(4)
5 * 4 * dec2FactString(3)
5 * 4 * 3 * dec2FactString(2)
5 * 4 * 3 * 2 * dec2FactString(1)
5 * 4 * 3 * 2 * 1 * dec2FactString(0)
5 * 4 * 3 * 2 * 1 * "1"

... That is the point where the recursion ends in an error since dec2FactString(0) returns "1" ...因为dec2FactString(0)返回“ 1”,所以递归以错误结束

It would be far better to break it into two functions. 最好将其分为两个功能。 One that calculates factorial recursively and one that converts the final answer to a string. 一种递归计算阶乘,一种将最终答案转换为字符串。 Also, you don't need to explicitly return a value in Ruby. 另外,您不需要在Ruby中显式返回值。 The last line of a function is the return value. 函数的最后一行是返回值。

I won't give you the complete code as you won't learn anything. 我不会给你完整的代码,因为你不会学任何东西。 As a few hints, do some research on tail call optimisation, recursion and return values in Ruby. 作为一些提示,请对Ruby中的尾部调用优化,递归和返回值进行一些研究。 This will allow you to craft a better implementation of the recursive function. 这将使您可以更好地实现递归函数。

Happy coding! 编码愉快!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM