1

Was wondering if there is a way to write a method which squares a number (integer or decimal/float) without using the operational sign (*). For example: square of 2 will be 4, square of 2.5 will be 6.25, and 3.5's will be 12.25.

Here is my approach:

def square(num)
  number = num
  number2 = number
  (1...(number2.floor)).each{ num += number }
  num
end

puts square(2) #=> 4 [Correct]
puts square(16) #=> 256 [Correct]
puts square(2.5) #=> 5.0 [Wrong]
puts square(3.5) #=> 10.5 [Wrong]

The code works for integers, but not with floats/decimals. What am I doing wrong here? Also, if anybody has a fresh approach to this problem then please share. Algorithms are also welcome. Also, considering performance of the method will be a plus.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Surya
  • 15,703
  • 3
  • 51
  • 74

3 Answers3

10

There are a few tricks you could use, arranged here in order of increasing trickery.

Logarithms

Observe that k * k = e^log(k*k) = e^(log(k) + log(k)), and use that rule:

Math.exp(Math.log(5.2) + Math.log(5.2))
# => 27.04

No multiplication here!

Division

As another commenter suggested, you could take the reciprocal operation, division: k/(1.0/k) == k^2. However, this introduces additional floating-point errors, since k / (1.0 / k) is two floating-point operations, whereas k * k is only one.

Exponentiation

Or, since this is Ruby, if you want exactly the same value as the floating-point operation and you don't want to use the multiplication operator, you can use the exponentiation operator: k**2 == k * k.

Call a web service

It's not multiplying if you don't do it yourself!

require 'wolfram'       # https://github.com/cldwalker/wolfram
query  = 'Square[5.2]'
result = Wolfram.fetch(query)

Blatant cheating

Finally, if you're feeling really cheap, you could avoid actually employing the literal "*" operation, and use something equivalent:

n = ...
require 'base64'
n.send (Base64.decode64 'Kg==').to_sym, n    # => n * n
John Feminella
  • 303,634
  • 46
  • 339
  • 357
  • @John - Division has to be: `k/(1.0/k) == k^2` as `1/k` in `k/(1/k) == k^2` will output an integer instead of a decimal value. @CarySwoveland - I tried `Math.exp(Math.log(5.2) + Math.log(5.2)) #=> 27.04` where as `5.2*5.2 = 27.040000000000003` Which is almost equal if we consider 3 decimal points to be exact. Don't you think? – Surya Jan 06 '14 at 06:31
  • @CarySwoveland: Ah, yes, I only meant to imply that the specific example I was using gives the mathematically exact value -- not that it was true for every value. – John Feminella Jan 06 '14 at 06:34
4

Didn't use any operation sign.

def square(num)
  num.send 42.chr, num
end
xdazz
  • 158,678
  • 38
  • 247
  • 274
3

Well, the inverse of multiplication is division, so you can get the same result* by dividing by its inverse. That is: square(n) = n / (1.0 / n). Just make sure you don't inadvertently do integer division.

*Technically dividing twice introduces a second opportunity for rounding error in floating-point arithmetic since it performs two operations. So, this will not produce exactly the same result as floating-point multiplication - but this was also not a requirement in the question.

lc.
  • 113,939
  • 20
  • 158
  • 187
  • 1
    That's not equivalent to floating-point multiplication. You made two divisions and accumulated 2 errors (`1/n`, `n/(1/n)`) instead of 1 error (`n * n`). If you define `def s(n); n / (1.0 / n);`, you'll get `s(5.1) == 26.009...994` and `5.1**2 == 26.009...998`, which are not equal values. – John Feminella Jan 06 '14 at 05:31
  • @JohnFeminella Valid point, however the OP doesn't specify this as a requirement – lc. Jan 06 '14 at 05:34
  • Sure, but if one doesn't require "exact answers", then *any* answer is correct, even wrong ones. Then it's just a question of how wrong is acceptable. :) – John Feminella Jan 06 '14 at 05:35
  • @JohnFeminella Quite true, and point well taken. Although with floating-point arithmetic you don't end up with "exact answers" anyway, do you? :) The question would then go back to why would the OP want to avoid the `*` operator in the first place. – lc. Jan 06 '14 at 05:39
  • As @JohnFeminella mentioned. When I tried with (`1/n`, `n/(1/n)`) and it raised **ZeroDivisionError**. So, it has to `(`1.0/n`, `n/(1.0/n)`)` So, it takes the decimal number instead of integer. Nice catch. :) – Surya Jan 06 '14 at 06:29