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.
*
works with traditionally.def multiply(a, b) result = 0 a.times { result += b} result end
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
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
#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
puts sum + b
, I got undefined method '+' for nil:NilClass (NoMethodError)
, which surprised me. Is this something you would have expected?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.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: