# Ruby coding challenges

### Joshua Summers

I'm the founder of Taaalk and a Ruby on Rails engineer

### Robert Heaton

Software Engineer at Stripe. Blog at robertheaton.com

3 followers

604 views

Joshua Summers
10:21, 09 Apr 22
In this Taaalk we will solve some Ruby coding challenges together. I'm going to use this list of advanced Ruby coding challenges on codecademy.
Challenge one is:
1. Re-inventing multiplication
In this challenge, write a function in Ruby that takes two parameters, both of them are numbers. The function should multiply the numbers and return the result, but there’s a catch. You’re not allowed to use the * symbol.
Let me know when you've had a think about it and then we will both reveal our solutions.
Robert Heaton
17:43, 09 Apr 22
Sounds good! What inputs are we allowing? Do they have to be integers or can they be any of the decimal types? Can they be negative?
Joshua Summers
23:35, 09 Apr 22
Anything that `*` works with traditionally.
Joshua Summers
10:57, 10 Apr 22
Let's also say you can return the answer in the format of your choice.
Joshua Summers
12:19, 10 Apr 22
Robert Heaton
12:25, 10 Apr 22
OK! I have some solutions ready.
Joshua Summers
12:27, 10 Apr 22
```def multiply(a, b)
result = 0
a.times { result += b}
result
end```
Robert Heaton
12:46, 10 Apr 22
```def multiply_ints_properly(x, y)
# We want to use `x.times` to sum x copies of y, but if
# x < 0 then this won't work. We therefore use the absolute
# value of x and flip the sign if necessary.
ans_using_abs_x = x.abs.times.inject(0) {|acc, _| acc + y}
x < 0 ? -ans_using_abs_x : ans_using_abs_x
end```
Robert Heaton
12:47, 10 Apr 22
My toddler wouldn't go to sleep last night so I also have 4 sillier answers:
```def multiply_hack1(x, y)
# It's a mathematical identity that:
#
#   x * y == x / (1.0 / y)
#
# 1.0 / y is a `Float` so this solution is not fully
# accurate for most inputs.
#
# We should technically look at what the types of x and
# y were and return the answer as that type too.
x / (1.0 / y)
end

def multiply_hack2(x, y)
# Another mathematical identity:
#
#   x * y == Math.exp(Math.log(x) + Math.log(y))
#
# Again, `Math.log` returns a `Float` which loses some
# precision, so in practice this seems to only be
# accurate to about 15 sig figs.
#
# Also again, we should  look at what the types of x and
# y were and return the answer as that type.

# We need to handle 0 as a special case since `log(0)` is
# undefined.
return 0 if x == 0 || y == 0

# If x and/or y are negative then we need to handle that
# ourselves too, since `log(x)` is a complex number if x < 0.
#
# We get around this by taking the log of the absolute
# values, then making the answer negative if exactly one of
# x and y are negative (XOR - the ^ operator).
abs_ans = Math.exp(Math.log(x.abs) + Math.log(y.abs))
(x < 0) ^ (y < 0) ? -abs_ans : abs_ans
end

def multiply_hack3(x, y)
# 42 is the ASCII code for `*`, so this just calls `*`
# while technically not useing the `*` symbol. This one
# is the most correct of all the solution.
x.send(42.chr, y)
end

def multiply_hack4(x, y)
# Use a maths API
require 'uri'
require 'net/http'

uri = URI("http://api.mathjs.org/v4/?expr=#{x}#{42.chr}#{y}")
res = Net::HTTP.get_response(uri)
if res.is_a?(Net::HTTPSuccess)
res.body.to_f
else
raise "Failed to multiply #{x} and #{y}"
end
end

# Tests
inputs = [
[5, 9],
[-3, -4.5],
[900, 235],
[32.2179, -87.11],
[2893217361128, 0]
]

inputs.each do |inp|
puts "#{inp[0]} * #{inp[1]} = #{inp[0] * inp[1]}"
(1..4).each do |m|
puts "multiply_hack#{m}: " + send("multiply_hack#{m}", *inp).to_s
end
puts ""
end
```
Joshua Summers
13:14, 10 Apr 22
I'm so ashamed I didn't write tests and put myself in a position to make it clear my method would fail with negative integers! Sloppy of me 🙈
I was just refactoring my code, experimenting with `#inject` / `#reduce`, and I noticed something odd. While this runs without any errors:
```def multiply(a, b)
a.times.inject(0) { |sum, _| sum + b }
end```
When I tried to `puts sum + b` , I got `undefined method '+' for nil:NilClass (NoMethodError)`, which surprised me. Is this something you would have expected?
Robert Heaton
13:57, 10 Apr 22
No shame!
Yep, that's because `puts` returns `nil`, so the accumulator will have the value `nil` on the second time through. Try `ans = sum + b; puts ans; ans` or something like that.