Oswald Roswell
Oswald Roswell

Reputation: 65

Comparing signs of Fixnums in Ruby

I want to compare just the signs of two Fixnums. Right now I am using:

c = -c if (a >= 0.0 && b < 0.0) || (a < 0.0 && b >= 0.0)

I would like something like:

c = -c if a.sign != b.sign

or perhaps some other way of comparing only the signs.

Upvotes: 0

Views: 86

Answers (3)

the Tin Man
the Tin Man

Reputation: 160549

This question made me start rooting around in my assembler toolbox, which I haven't had open for years. I think this'll do what you're looking for:

c = -c if (a < 0) ^ (b < 0)

Here's what it's doing:

irb(main):006:0> true ^ true
=> false
irb(main):007:0> true ^ false
=> true
irb(main):008:0> false ^ true
=> true
irb(main):009:0> false ^ false
=> false

Depending on your code, an alternate way is to use it could be in a ternary statement:

((a < 0) ^ (b < 0)) ? -c : c

Here's some benchmark code and results:

require 'benchmark'

puts `ruby -v`

N = 10_000_000

A = 1
B = 1
Benchmark.bm(5) do |bench|
  bench.report('^') { N.times { (A < 0) ^ (B < 0) } }
  bench.report('!=') { N.times { (A>=0) != (B>=0) } }
  bench.report('<') { N.times { A*B < 0 } }
end

ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-darwin12.2.0]
            user     system      total        real
^       5.740000   0.000000   5.740000 (  5.743873)
!=      4.300000   0.000000   4.300000 (  4.304685)
<       3.310000   0.000000   3.310000 (  3.312378)

ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-darwin12.2.0]
            user     system      total        real
^       1.480000   0.000000   1.480000 (  1.484879)
!=      1.400000   0.000000   1.400000 (  1.401381)
<       1.260000   0.000000   1.260000 (  1.256628)

That's with 10M loops, which is a heap o' looping. Looks like it's steenslag FTW!

Upvotes: 0

You could use a >= 0 for a similar purpose as "a.sign", with true for positive (non-negative) and false for negative:

c = -c if (a>=0) != (b>=0)

If you're using it often, and you want a more Ruby-esque feel, it might be worth your while to go with the comment above and patch this in, as something like Numeric#pos? maybe.

Upvotes: 2

steenslag
steenslag

Reputation: 80065

Maybe just multiplication:

c = -c if a*b < 0

Upvotes: 3

Related Questions