Please explain Ruby's square root (sqrt) value comparison - ruby

I have a Ruby class that compares the size of two values of x and y by inheriting the built-in module Comparable and sqrt methods. But unfortunately, I don't understand what def scalar in the code is calculating?
In the example below, Ruby's execution results in that v1 is greater than v2, but if I print the results of v1 and v2 alone, I get nothing but nonsense. So my second question is, what are the resulting values for v1 and v2?
class Vector
include Comparable
attr_accessor :x, :y
def initialize(x, y)
#x, #y = x, y
end
def scalar
Math.sqrt(x ** 2 + y ** 2)
end
def <=> (other)
scalar <=> other.scalar
end
end
v1 = Vector.new(2, 6)
v2 = Vector.new(4, -4)
puts v1 #=> #<Vector:0x000055a6d11794e0>
puts v2 #=> #<Vector:0x000055a6d1179490>
p v1 <=> v2 #=> 1
p v1 < v2 #=> false
p v1 > v2 #=> ture

Math.sqrt(x ** 2 + y ** 2) is using good old Pythagoras to calculate the Cartesian distance of the vector's endpoint from the origin, i.e., the length of the vector. For v1 this is 6.324555320336759, and for v2 the result is 5.656854249492381.
To inspect a Ruby object use p rather than puts.
p v2 # <Vector:0x0000000109a1eb40 #x=4, #y=-4>

what are the resulting values for v1 and v2?
Override to_s
class Vector
def to_s
"x = #{x} : y = #{y} : scalar = #{'%.6f' % scalar}"
end
end #Vector
And you get this output:
puts v1 # => x = 2 : y = 6 : scalar = 6.324555
puts v2 # => x = 4 : y = -4 : scalar = 5.656854

scalar would be better named magnitude because it is calculating the length of a vector using the Pythagorean Theorem. If you are unfamiliar with vectors and Pythagorean Theorem, I suggest you study the mathematical concepts here before you continue with much more code. Those concepts will be critical in understanding how they are used in code.

Related

Iterate through alphabet in Ruby until X

When using input x, I'm trying to iterate through the alphabet through to that point so, if I put in 44, I'll iterate to 18 from this method.
I can see a lot of methods on SO for iteration a..z, a..zzz, etc, but less for iteration to position x and outputting the associated letters. Is there a ruby method for flipping an input letter to a number within a dynamic range?
def get_num(x)
pos = x%26
(1..pos).each do |c|
puts c
#outputs letter for position c
# end
end
get_num(44) # => Expected: 44%26 = 18; iterate 1 to 18 (pos) to get A..R list as output.
Using the #Integer.chr method, 'a'..'z' == 97..122, and 'A'..'Z' == 65..90 That means:
def get_num(x)
pos = x%26
(96+pos).chr
end
get_num(44)
#=> "r"
OR
def get_num(x)
pos = x%26
(64+pos).chr
end
get_num(44)
#=> "R"
So, to complete your method:
def get_num(x)
pos = x%26
(1..pos).each do |c|
puts (c+64).chr
end
end
get_num(44)
#=>
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R

Iterate over array and first again

In order to export the coordinates of a polygon with n points I need to have n+1 points. The additional one is supposed to "close" the polygon. Currently I simply iterate over the whole array and do it manually again for the first:
face.outer_loop.vertices.each do |g|
xml.Grafic(
:X=>g.position.x,
:Y=>g.position.y,
:Z=>g.position.z)
end
xml.Grafic(
:X=>face.outer_loop.vertices[0].x,
:Y=>face.outer_loop.vertices[0].y,
:Z=>face.outer_loop.vertices[0].z)
Is there a more elegant solution?
I can think about:
COORDS = %i(X Y Z)
(face.outer_loop.vertices + [face.outer_loop.vertices.first]).each do |g|
values = COORDS.map do |c|
g.position.public_send "#{c.to_s.downcase}"
end
xml.Graphic COORDS.zip(values).to_h
end
or use each_with_object to not pollute coords in the global namespace:
(face.outer_loop.vertices + [face.outer_loop.vertices.first]).each_with_object(%i(X Y Z)) do |g, coords|
values = coords.map do |c|
g.position.public_send "#{c.to_s.downcase}"
end
xml.Graphic coords.zip(values).to_h
end

How can I calculate the intersection of two ordinary intervals in Ruby?

Intervals are given by their boundaries as arrays [a,b] and [x,y]. I would like to calculate the length of the intersection between them. According to this page: http://world.std.com/~swmcd/steven/tech/interval.html
I can tell it is 0 if
(not (a < y && x < b))
holds.
For example interval [1.2,4.3] and [2.1,5.5] intersection length is 4.3 - 2.1 = 2.2
This should do it.
Code
def length(a,b,p)
[[a.last,b.last].min - [a.first,b.first].max,0].max.round(p)
end
Examples
This is an OO solution of the same problem. I suggest to build a custom Interval class, but this implementation is only an example and the asker should think it over with respect to his actual case:
class Interval
attr_reader :range
def initialize range
#range = if range.nil? then nil else
fail TypeError, "Begin greater than end!" if range.begin > range.end
Range.new( range.begin, range.end )
end
end
def - other
begin
self.class.new [ range.begin, other.range.begin ].max ..
[ range.end, other.range.end ].min
rescue TypeError
self.class.new nil
end
end
def size
range.nil? ? 0 : range.end - range.begin
end
end
def Interval a, b # a convenience constructor
Interval.new a .. b
end
( Interval( 1.2, 4.3 ) - Interval( 2.1, 5.5 ) ).size
#=> 2.199999999999997
just for future reference - in MySQL Cary`s answer would be (without the rounding part):
GREATEST( LEAST(`a_last`, `b_last`) - GREATEST(`a_first`, `b_first`), 0 )

replacing 'eval' with a better solution

This method works, but it works very slowly. I think one of the problems might be the 'eval' statements in the add_by method.
Some explanation: every Node object has three relevant attributes, :x, :y and :neighbors. :x and :y are integers representing planar coordinates, :neighbors is an array, and nodes are stored in the #nodes array. The goal is to find, for each node k in #nodes, the nodes that are within some distance d of k and add them to the #neighbors array of k.
def set_neighbors d
def add_by dim, d
dict = {}
#nodes.each{|k| dict[k] = []}
#nodes.each_index do |k|
up = k+1
down = k-1
while up < #nodes.length and ((eval '#nodes[k].'+ dim) - (eval '#nodes[up].'+dim)).abs <= d
dict[#nodes[k]].push(#nodes[up])
up += 1
end
while down >= 0 and ((eval '#nodes[k].'+ dim) - (eval '#nodes[down].'+dim)).abs <= d
dict[#nodes[k]].push(#nodes[down])
down -= 1
end
end
return dict
end
#nodes.sort_by{|k| k.x}
exis = add_by('x', d)
whys = add_by('y', d)
#nodes.each do |k|
neighbors = exis[k]&whys[k]
k.neighbors = neighbors.select{|j| planar_distance(j,k) <= d}
end
end
My question is, how would you do this without either repeating the add_by routine for x and y or using eval?
You can avoid eval by using #nodes[k].send dim.to_sym.
I'm not sure what your code is doing exactly, but maybe a few pointers:
def set_neighbors d
#nodes.each do |node|
node.neighbors = #nodes.select do |n|
(node.x - n.x).abs <= d &&
(node.x - n.x).abs <= d &&
planar_distance(n,node) <= d
end - node
end
end
How would I do it? I'd use the Neo4J graph database via the neo4j gem (source). If you're concerned about performance, this is optimized for graph distance calculations. Also the API is very nice.
That being said, you really don't need eval at all. You can call a calculated method name on an object by using send. So you can replace the above with #nodes[k].send(dim), #nodes[up].send(dim), etc.

Syntax Error in Ruby, Unexpected Pipe Character in a Do

I'll try to be concise this time around! I'm still working Project Euler, this time back to #2. My real issue here is I'm terrible with Ruby. When I run the following code
x = 1
y = 2
sum = 2
while x >= 4_000_000 do |x|
sum += y if y % 2 == 0
z = x + y
x = x ^ y # xor magic
y = x ^ y # xor magic
x = x ^ y # xor magic
y = z
end
p sum
My interpreter kicks out the following output:
/Users/Andy/Documents/Programming/Ruby/ProjectEuler/P2.rb:4: syntax error, unexpected '|'
while x >= 4_000_000 do |x|
                         ^
I'm reading why's (Poignant) Guide to Ruby, and I'm pretty sure I have the pipe syntax correct for the Do. Could someone point out what I'm doing wrong here? I've tried messing around in a lot of different ways and am coming up short handed
while (x >= 4_000_000)
foo
end
You don't even have to pass in x, because it's accessible in the scope of the enclosing block.
while does not take a block. Remove the do |x| part.
while is not a method that takes a block, it is a ruby looping statement. It considers the part between the while and do (or newline) to be the logical test and the part between the do (or newline) and end keyword to be the loop body.
while x < 10 do x += 1; puts x; end
while x < 10
x += 1
puts x
end
Contrast this with something like the Array's each method which takes in a block. Here the each method calls your block for each element of the array (passed into the block as x)
[1,2,3].each do |x|
puts x
end
You accidentally combined the two, asking the while loop to call your code block with the loop counter to be passed in as x. That is not how while works... hence the parsing exception.
What an interesting question! It inspired me to take a shot at the problem, too. Here's my solution.
First, some preparatory work:
class Enumerator
def lazy_select
Enumerator.new do |y|
each do |el|
y.yield(el) if yield el
end
end
end
alias_method :lazy_find_all, :lazy_select
end
module Enumerable
def sum
reduce(:+)
end
end
module Math
ROOT5 = Math.sqrt(5)
PHI = 0.5 + ROOT5/2
def self.fibonacci(n)
Integer(0.5 + PHI**n/ROOT5)
end
end
class Integer
def fibonacci
Math.fibonacci(self)
end
end
Now an Enumerator which generates an infinite sequence of Fibonacci Numbers:
fibs = Enumerator.new do |y|
n = -1
loop do
y.yield (n += 1).fibonacci
end
end
And the nice thing is that we can now directly express the original problem statement in code:
Find the sum of all the even-valued terms in the sequence which do not exceed four million.
puts fibs.lazy_find_all(&:even?).take_while {|n| n <= 4_000_000 }.sum
I think that this is a much more Rubyish way to solve the problem. You write in your question that you are terrible with Ruby. But that's not actually the problem. The real problem is that you are good with C! In other words, the real problem is that you simply aren't writing Ruby, you are writing C with Ruby syntax.
Two good examples are:
y % 2 == 0
and
x = x ^ y
y = x ^ y
x = x ^ y
The Ruby way to write these would be
y.even?
and
x, y = y, x

Resources