I'm working on a Codewars Ruby problem, and don't understand the error I'm seeing. 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!.
The digit before that is either 0 or 1 and is in base 1!. The digit
before that is either 0, 1, or 2 and is in base 2!. More generally,
the nth-to-last digit in always 0, 1, 2, ..., or n and is in base n!.
Example : decimal number 463 is coded as "341010"
because 463 (base 10) = 3×5! + 4×4! + 1×3! + 0×2! + 1×1! + 0×0!
If we are limited to digits 0...9 the biggest number we can code is
10! - 1.
So we extend 0..9 with letters A to Z. With these 36 digits we can
code up to 36! − 1 = 37199332678990121746799944815083519999999910
(base 10)
We code two functions, the first one will code a decimal number and
return a string with the factorial representation :
"dec2FactString(nb)"
the second one will decode a string with a factorial representation
and produce the decimal representation : "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.
Ref: 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:
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. 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. 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.
However, if you do place to_s in there, what would you expect the result of num = (nb * dec2FactString(nb - 1)) to be? 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.
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). The recursion should stop when the number is 0 and should return 1 at that point.
Because your recursion returns a string and not a number, you cannot multiply the string by a Fixnum in the next round of recursion. 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"
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. 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. This will allow you to craft a better implementation of the recursive function.
Happy coding!
Related
I was solving Sam and substrings problem from hackerrank. It is basically finding sum of all substrings of a string having all integers.
Samantha and Sam are playing a numbers game. Given a number as a string, no leading zeros, determine the sum of all integer values of substrings of the string.
Given an integer as a string, sum all of its substrings cast as integers. As the number may become large, return the value modulo 10⁹ + 7.
Example: n = '42'
Here n is a string that has three integer substrings: 4, 2, and 42. Their sum is 48, and 48 modulo 10⁹ + 7 = 48.
Function Description
Complete the substrings function in the editor below.
substrings has the following parameter(s):
string n: the string representation of an integer
Returns
int: the sum of the integer values of all substrings in n, modulo (10⁹ + 7)
I tried following recursive top down dynamic problem solution with memoization:
from functools import cache
def substrings(n):
#cache
def substrSum(curIndex):
if curIndex == 0: return int(n[0])
return substrSum(curIndex-1)*10 + int(n[curIndex]) * (curIndex+1)
totalSum = 0
for i in range(len(n)-1, -1,-1):
totalSum += substrSum(i)
return totalSum % (10 ** 9 + 7)
I also tried recursive bottom up dynamic programming solution with memoization (this simply involves changing for loop counting direction):
from functools import cache
def substrings(n):
#cache
def substrSum(curIndex):
if curIndex == 0: return int(n[0])
return substrSum(curIndex-1)*10 + int(n[curIndex]) * (curIndex+1)
totalSum = 0
for i in range(len(n)):
totalSum += substrSum(i)
return totalSum % (10 ** 9 + 7)
For top-down solution gives runtime error in 8 out of 13 test cases, whearas in bottom up solution gives gives runtime error in 6 out of 13 test cases. Where am I making mistake?
Your algorithm is correct (both versions), but HackerRank will test with strings that have many thousands of digits, and as you perform a recursive call for each digit, your first code runs into a maximum recursion depth exceeded error, and the second one runs into a memory error (think of the cache).
It should be noted that they phrased the constraint wrong. It is not the value of n "cast to integer" that is limited by 2 x 105, but the number of digits in n. I checked this, and one of their tests concerns a string of about 199000 digits.
This question already has answers here:
Why is division in Ruby returning an integer instead of decimal value?
(7 answers)
Closed 3 years ago.
I am not understanding why my code isn't looping, for any input I give I get the result of "1.00"
I feel like I am being silly and missing something very obvious.
This series is shown in other places most often as 1/3n+1
But if series_sum(1) = "1.00"
then 3+1 = 4 giving you 1/4 to add to your sum for input of 1 which doesn't make sense
def series_sum(n)
sum = 0
if n == 0
return "0.00"
else
for i in 1..n
sum += 1/(1+(3*(i-1)))
end
end
return "%.2f" % sum.to_s
end
for series_sum(1) should be "1.00"
series_sum(2) should be "1.25"
series_sum(3) should be "1.39"
etc
My code gives "1.00" for any input
Why won't this code run the loop and perform the sum?
When you have expression like z = x/y, in ruby it does specify type for output based on operand provided for division. If x & y both are integer, output calculated is also integer and float value is removed.
So to obtain output as float, you need to have one operand at least as float value which can be found using to_f on variable. Here you need to change only,
- sum += 1/(1+(3*(i-1)))
+ sum += 1.0/(1+(3*(i-1)))
I need to do integer division. I expect the following to return 2 instead of the actual 1:
187 / 100 # => 1
This:
(187.to_f / 100).round # => 2
will work, but does't seem elegant as a solution. Isn't there an integer-only operator that does 187 / 100 = 2?
EDIT
I'll be clearer on my use case since I keep getting down-voted:
I need to calculate taxes on a price. All my prices are in cents. There is nothing below 1 cent in the accountability world so I need to make sure all my prices are integers (those people checking taxes don't like mistakes... really!)
But on the other hand, the tax rate is 19%.
So I wanted to find the best way to write:
def tax_price(price)
price * TAX_RATE / 100
end
that surely returns an integer, without any floating side effect.
I was afraid of going to the floating world because it has very weird side-effects on number representation like:
Ruby strange issue with floating point multiplication
ruby floating point errors
So I found it safer to stay in the integer or the fractional world, hence my question.
You can do it while remaining in the integer world as follows:
def round_div(x,y)
(x + y / 2) / y
end
If you prefer, you could monkey-patch Fixnum with a variant of this:
class Fixnum
def round_div(divisor)
(self + divisor / 2) / divisor
end
end
187.round_div(100) # => 2
No – (a.to_f / b.to_f).round is the canonical way to do it. The behavior of integer / integer is (for example) defined in the C standard as "discarding the remainder" (see http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf page 82) and ruby uses the native C function.
This is a less know method, Numeric#fdiv
You use it like this : 187.fdiv(100).round
Not sure, but this might be what you have in mind.
q, r = 187.divmod(100)
q + (100 > r * 2 ? 0 : 1) # => 2
This should work for you :
Use syntax like this.
(number.to_f/another_number).round
Example:
(18.to_f/5).round
As #MattW already answer (+1), you'd have to cast your integers to floats.
The only other way that is less distracting can be to add .0 to your integer:
(187.0 / 100).round
However, usually we don't operate on concrete integers but variables and this method would be no use.
After some thoughts, I could:
have used BigDecimals but it feels like a bazooka to kill a bird
or I can use a custom method that wouldn't use floating division within the process, as #sawa suggests
def rounded_integer_div(numerator, denominator)
q, r = numerator.divmod(denominator)
q + (100 > r * 2 ? 0 : 1)
end
If what you want is to actually only increase the result by 1 if there's any remainder (e.g. for counting paging/batching), you can use the '%' (modula operation) for remainders checking.
# to add 1 if it's not an even division
a = 187
b = 100
result = a / b #=> 1
result += 1 if (a % b).positive?
#=> 2
# or in one line
result = (a / b) + ((a % b).zero? ? 0 : 1)
For instance:
8 > 10 = true, since 8 is divisible by 2 three times and 10 only once.
How can I compare two integers from any range of numbers? Are the modulo and divide operator capable of doing this task?
Use binary caculate to judge it
def devided_by_two(i)
return i.to_s(2).match(/0*$/).to_s.count('0')
end
To make integer divisibility by 2, just transcode it to binary and judge how many zero from end of banary number. The code I provide can be more simple I think.
Yes, they are capable. A number is even if, when you divide it by two, the remainder is zero.
Hence, you can use a loop to continuously divide by two until you get an odd number, keeping a count of how many times you did it.
The (pseudo-code) function for assigning a "divisibility by two, continuously" value to a number would be something like:
def howManyDivByTwo(x):
count = 0
while x % 2 == 0:
count = count + 1
x = x / 2 # make sure integer division
return count
That shouldn't be too hard to turn into Ruby (or any procedural-type language, really), such as:
def howManyDivByTwo(x)
count = 0
while x % 2 == 0
count = count + 1
x = x / 2
end
return count
end
print howManyDivByTwo(4), "\n"
print howManyDivByTwo(10), "\n"
print howManyDivByTwo(11), "\n"
print howManyDivByTwo(65536), "\n"
This outputs the correct:
2
1
0
16
Astute readers will have noticed there's an edge case in that function, you probably don't want to try passing zero to it. If it was production code, you'd need to catch that and act intelligently since you can divide zero by two until the cows come home, without ever reaching an odd number.
What value you return for zero depends on needs you haven't specified in detail. Theoretically (mathematically), you should return infinity but I'll leave that up to you.
Notice that you will likely mess up much of your code if you redefine such basic method. Knowing that, this is how it's done:
class Integer
def <=> other
me = self
return 0 if me.zero? and other.zero?
return -1 if other.zero?
return 1 if me.zero?
while me.even? and other.even?
me /= 2
other /= 2
end
return 0 if me.odd? and other.odd?
return -1 if me.odd?
return 1 if other.odd? # This condition is redundant, but is here for symmetry.
end
end
I was given this problem to solve with Ruby:
Compute the sum of cubes for a given range a through b. Write a method called sum_of_cubes to accomplish this task.
I wrote this:
def sum_of_cubes(a, b)
sum = 0
for x in a..b
c = x ** 3
end
sum += c
end
I got the value of the cube of b. What is wrong with this code? How can I solve this problem with a simple loop?
Thanks!
I would use Enumerable#reduce
def sum_of_cubes min, max
(min..max).reduce(0) { |a, b| a + b ** 3 }
end
A little explanation of what's happening here
We start with range (min..max) which is an Enumerable
irb> (1..3).is_a? Enumerable
=> true
Using the reduce instance method we get from Enumerable, we can use a block of code that gets called for each item in our (enumerable) range, and ultimately returns a single value.
The function name makes sense if you think "take my group of items and reduce them to a single value."
Here's our block
{ |a, b| a + b ** 3 }
We called reduce with 0 which is the initial value given to the block's a param
The return value of the block is passed to the block's a param on subsequent calls
Each item in the range will be passed to the block's b param
Let's step through and see how it works
(1..3).reduce(0) { |a, b| a + b ** 3 }
the first block call gets a=0 (initial value) and b=1 (first item in our range)
the return value of our block is 0 + 1 ** 3 or 1
the second block call gets a=1 (return value from the last call) and b=2 (the second item in our range)
the return value of our block is 1 + 2 ** 3 or 9
the third block call gets a=9 (return value from the last call) and b=3 (the third and last item in our range)
the return value of our block is 9 + 3 ** 3 or 36
the final return value of reduce is the last-called block's return value
in this case 36
You need to have sum += c inside the loop. And then return sum when done.
Here’s another way to calculate this. It doesn’t address your problems with your loop but I think it’s worth mentioning.
The sum of cubes of integers 13 + 23 + 33 + ... + n3 is given by the formula (n(n + 1)/2)2, so the sum of cubes of a given range min..max is therefore given by:
(max(max + 1)/2)2 - ((min-1)((min-1) + 1)/2)2
In code this could look like:
def sum_of_cubes_fixed min, max
lower = min - 1
(((max * (max + 1))/2) ** 2) - (((lower * (lower + 1))/2) ** 2)
end
This code avoids the loop, and so is O(1) rather than O(n) (almost – I’m hand waving a bit here, the time complexity of the multiplications and exponentiations will depend on the size of the numbers). For small sized ranges you won’t notice this, but for larger sizes the difference between this and the loop version becomes increasingly obvious. I haven’t done any strict benchmarks, but a quick test on my machine with the range 1 to 10,000,000 takes several seconds with the reduce method but is almost instantaneous with this method.
Normally I would just use reduce for something like this, but the structure of the task suggested that there might be a better way. With the help of Google I found the formula and came up with a more efficient solution (at least for large ranges).
(a..b).map{|i| i**3 }.inject(&:+) map and inject does the job, elegantly.
EDIT: Although it walks through the list twice ;)