Methods don't know about outside variables? - ruby

Say I'm writing a division algorithm script:
def current_trace
puts "Counter: #{counter}; r: #{r}; q: #{q}"
end
r = a
q = 0
counter = 0
while r >= d
current_trace
r = r - d
q = q + 1
counter += 1
end
current_trace
I expected that calling current_trace would output the value of counter, r and q. But instead I get:
in current_trace': undefined local variable or methodcounter' for main:Object (NameError)
What's the problem here?
How should I write a method that will output the values of some variables named counter, r, and q, at any given point (preferably without passing arguments to the method)?

In this case, your current_trace method is so simple that it does not worth making it a method. But looking at your code, the reason you did so is probably because it appears more than once. That is the bad part of your code that should be improved. By reconsidering the timing of the conditional and puts, you can avoid calling puts in two different locations.
counter, q, r = 0, 0, a
loop do
puts "Counter: #{counter}; q: #{q}; r: #{r}"
break if r < d
counter += 1
q += 1
r -= d
end

The correct thing is to write your method so it accepts parameters:
def current_trace(c, r, q)
puts "Counter: #{ c }; r: #{ r }; q: #{ q }"
end
Then call it like:
d = 1
r = 5
q = 0
counter = 0
while r >= d
current_trace(counter, r, q)
r = r - d
q = q + 1
counter += 1
end
current_trace(counter, r, q)
Which results in:
Counter: 0; r: 5; q: 0
Counter: 1; r: 4; q: 1
Counter: 2; r: 3; q: 2
Counter: 3; r: 2; q: 3
Counter: 4; r: 1; q: 4
Counter: 5; r: 0; q: 5
(I tweaked your variable names because your code won't work because you don't show where a and d come from, but that's beside the point.)
You can use #instance, $global or CONSTANTs but those are playing games with variable scoping, which can cause problems when you accidentally change them in some method, often because you mistype them or leave off the sigil (#, $) and inadvertently create a local variable that doesn't change the one you want. Having to use #var, or $var at the main level, just to get your code to work, is a pretty good sign you're doing something wrong actually.

I think I figured it out. counter, r and q were (apparently) only local to main's scope. I changed them to the globals $counter, $r and $q, and now I have access to them in my method.
(Realized this here: https://stackoverflow.com/a/9389532/1468130)

Related

Why is the function not matching the call?

I have a function blur_1D(v, l) which takes a vector v and an integer l and for each value v[i] in v, it gets the mean of i-l to i+l and replaces v[i] to create a blur. My function isn't getting matched to the call. Here's the code.
function mean(x)
sum = 0.0
for i in 1:length(x)
sum += x[i]
end
return sum / length(x)
end
function extend(v, i)
n = length(v)
if i < 1
return v[1]
elseif i > n
return v[n]
else
return v[i]
end
end
function blur_1D(v, l)
blur_v = zeros(typeof(v[1]), length(v))
for i in 1:length(v)
box = zeros(typeof(v[i]), ((2*l)+1))
k = 1
for j in i-l:i+l
box[k] = extend(v, j)
k += 1
end
blur_v[i] = mean(box)
end
return blur_v
end
n = 100
v = rand(n)
begin
colored_line(x::Vector{<:Real}) = Gray.(Float64.((hcat(x)')))
colored_line(x::Any) = nothing
end
colored_line(blur_1D(v))
Why does it give me an error?
MethodError: no method matching blur_1D(::Array{Float64,1})
Closest candidates are:
blur_1D(::Any, !Matched::Any) at /Users/...
Please excuse any inefficient, inelegant code/syntax, but I do welcome suggestions on how I could improve that as well. :)
Perhaps the l parameter in your blur function has some default value and you normally want to use a one-parameter version.
In that case you should define function with a default value:
function blur_1D(v, l=0)
BTW, I strongly discourage using l for variable name because it can be easily be mistaken with 1 (one), especially when the code is read by somebody else.

Julia 1.0 UndefVarError - Scope of Variable

I am moving from Julia 0.7 to 1.0. It seems that Julia's rule for the scope of variables changed from 0.7 to 1.0. For example, I want to run a simple loop like this:
num = 0
for i = 1:5
if i == 3
num = num + 1
end
end
print(num)
In Julia 0.7 (and in most of other languages), we could expect num = 1 after the loop. However, it will incur UndefVarError: num not defined in Julia 1.0. I know that by using let I can do this
let
num = 0
for i = 1:5
if i == 3
num = num + 1
end
end
print(num)
end
It will print out 1. But I do want to get the num = 1 outside the loop and the let block. Some answers suggest putting all code in a let block, but it will incur other problems including UndefVarError while testing line-by-line. Is there any way instead of using let blocking? Thanks!
This is discussed here.
Add global as shown below inside the loop for the num variable.
num = 0
for i = 1:5
if i == 3
global num = num + 1
end
end
print(num)
Running in the Julia 1.0.0 REPL:
julia> num = 0
0
julia> for i = 1:5
if i == 3
global num = num + 1
end
end
julia> print(num)
1
Edit
For anyone coming here new to Julia, the excellent comment made in the answer below by vasja, should be noted:
Just remember that inside a function you won't use global, since the scope rules inside a function are as you would expect:
See that answer for a good example of using a function for the same code without the scoping problem.
Just remember that inside a function you won't use global, since the scope rules inside a function are as you would expect:
function testscope()
num = 0
for i = 1:5
if i == 3
num = num + 1
end
end
return num
end
julia> t = testscope()
1
The unexpected behaviour is only in REPL.
More on this here

Erroneous dynamic programming algorithm

Transferred from Code Review. If this question is not suitable for SO either, please let me know. I will remove it.
I am working on an algorithm puzzle here at: https://www.hackerrank.com/challenges/hackerland-radio-transmitters/forum
It cannot pass all of the test cases. Some test cases have such large arrays that it gets so hard to debug. Simple cases from my end seem all work fine. Can anyone look into this and share what is wrong with this algorithm? Basically it just loops through the array and find every furthest covered station (as origin). A counter-like variable result record the origins (radio stations).
def solution(k, arr, origin=0):
arr = sorted(list(set(arr)))
result = 1
cur = 0
origin = 0
for i in range(1, len(arr)):
if arr[i] - arr[origin] <= k:
pass
else:
origin = i - 1
j = 1
while origin + j < len(arr):
if arr[origin + j] - arr[origin] <= k:
pass
else:
origin = origin + j
i = origin + j + 1
result += 1
continue
j += 1
return result
Most of your code is correct. Only problem is with the usage of For range outer loop and continue in the inner loop.
For range loop doesn't change the i value # runtime (it is more like a ForEach loop).
The continue will not terminate the inner loop - you may want to use break.
The following code passed all the test cases
def solution(k, arr, origin=0):
arr = sorted(list(set(arr)))
print arr
result = 1
cur = 0
origin = 0
i = 0
while (i < len(arr)):
if arr[i] - arr[origin] <= k:
i = i + 1
pass
else:
origin = i - 1
j = 1
while origin + j < len(arr):
if arr[origin + j] - arr[origin] <= k:
pass
else:
# Start for next station position from this point
i = origin + j
origin = i
# need another radio station
result += 1
break
j += 1
return result
hope it helps!
You're placing the first object on the first index. The first object in the optimal solution can be placed later too.
solution(1,[1,2,3,4,5,6]) prints 3, when it should be 2 (by placing the two objects on 2 and 5). You place your first object on 1, then 3 and then 5. It should ideally be placed on 2, then 5.

Pseudocode for adding 2 until number is 100

I have a pseudocode assignment for a class. I have to design a program to output every even number starting with 2 and going to 100. I need someone to tell me if this is correct. If it isn't could someone point me in the right direction?
start
Declarations
num A = 0
num B = 100
num C
while A < B
C = A + 2
Output C
Endwhile
stop
start
Declarations
num A = 0
num B = 100
while A < B
A = A + 2
Output A
Endwhile
stop

Calculating pi using iterations in ruby

For a school's assignment I am trying to calculate pi using the Gauss Legendre algorithm to test cpu efficiency.
Therefore, I have written a program in Ruby.
This program should iterate 500000000 times and display the the time used for it. But everytime it executes within a second.
My question:
Is there a better way to iterate so it really does repeat 500 million times and display pi and the time?
include Math
a = 1
b = 1/sqrt(2)
t = 0.25
p = 1
i = 0
imax = 500000000
start = Time.now
until i = imax
an = (a/2) + (b/2)
bn = sqrt(a) * sqrt(b)
tn = t - p * ((a-an) * (a-an))
pn = 2 * p
a = an
b = bn
t = tn
p = pn
i +=1
PI = ((a+b)*(a+b))/(4*t)
end
finish = Time.now
time = finish - start
puts PI
puts time
Start by not making i equal imax right away:
until i = imax
Should be
until i == imax
Even better, just do
500000000.times do
Instead of that line.
In addition to the issues raised by #Nick and #sawa your algorithm is flawed: the square root of the product of a and b is not equal to the product of the square roots of a and b.
In ruby:
include Math
a, b, t, p = 1, 1/sqrt(2), 0.25, 1
imax = 5
imax.times do |i|
an = (a+b) / 2
bn = sqrt(a * b)
tn = t - p * ((a-an) * (a-an))
pn = 2 * p
a, b, t, p = an, bn, tn, pn
pi = ((a+b)*(a+b))/(4*t)
printf "%d : %10.60f\n", i, pi
end
Running this gives me:
0 : 3.140579250522168575088244324433617293834686279296875000000000
1 : 3.141592646213542838751209274050779640674591064453125000000000
2 : 3.141592653589794004176383168669417500495910644531250000000000
3 : 3.141592653589794004176383168669417500495910644531250000000000
4 : 3.141592653589794004176383168669417500495910644531250000000000
So clearly you need more accuracy, hence BigDecimal. As this is your homework assignment I'll leave that up to you :-). (If unsure which variables to change, try all except i and imax. Also check out http://www.ruby-doc.org/stdlib-1.9.3/libdoc/bigdecimal/rdoc/BigDecimal.html)
Another thing you are doing wrong is assigning a constant PI within a loop. Although it is possible to reassign a constant, it is not correct to do so. Either use a variable or move the assignment to outside of the loop so that it would be assigned only once.
Even if I remove the assignment and print out the result for each iteration like this:
include Math
a = 1
b = 1/sqrt(2)
t = 0.25
p = 1
i = 0
imax = 500000000
until i == imax
an = (a/2) + (b/2)
bn = sqrt(a) * sqrt(b)
tn = t - p * ((a-an) * (a-an))
pn = 2 * p
a = an
b = bn
t = tn
p = pn
i +=1
puts ((a+b)*(a+b))/(4*t)
end
I get the wrong result. It goes like this:
-2.1244311544725596
-1.1383928808463357
-1.1265990444799223
-1.1265961703346379
-1.126596170334544
-1.126596170334544
... # very long repetition of the same number
-1.126596170334544
-1.126596170334544
NaN
NaN
... # NaN forever
Something must be wrong with your algorithm.

Resources