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

Software Engineer at Stripe. Blog at robertheaton.com

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 multiplicationIn 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

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

Actually, scratch that. I think we should start with integers and gradually expand the solution.

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

Your turn.

Robert Heaton

12:46, 10 Apr 22

I have one serious answer:

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.
Taaalk

Conversations are one of the core pillars of human interaction. They are fundamental to how we collaborate, pass on knowledge, and understand, as well as be understood by, one another.

Taaalk is based on the belief that long-form conversations between people deserve their own space on the web. To make this space the best it can be, you are invited to discuss ideas and feedback you have about the website in our open "Taaalk feedback" conversation.

About

By using this website you agree to our: