A highly fascinating function I’m writing requires, at one point, I create a vector of length nv that contains the result of this calculation:
abs(2*mod(q[i-1]+rand(),1)-1)
That is, each row needs to start with a random uniform value (a new one generated for each row), then you add q[i-1] to it, then take that result mod(,1) [which just takes the decimal result, e.g., mod(1.23,1) = 0.23], multiply it by 2, then subtract 1.
I haven’t been able to figure out how to do that in 1 step with Julia. Below is a snippet of code that illustrates the calculation, but it requires 2 lines of code to compute the x vector.
function tune()
q = [1.41421356, 1.73205080, 2.23606798]
nv = 5
for i in 2:4
x=rand(1,nv)
x=abs.(2*mod.(x .+ q[i-1],1) .- 1)
# other fascinating code follows
println(x)
end
end
You missed a dot: 2 .* mod. Forgetting this will create an extra allocation. Also, since you are reusing x you can dot the assignment as well. Often it’s best to use the @. macro so you don’t miss any dots:
x = rand(nv)
@. x = abs(2 * mod(x + q[i-1], 1) - 1)
For negative numbers this isn’t quite the case:
julia> mod(-0.2, 1)
0.8
On the other hand, rem does this (and is faster, too):
julia> rem(-0.2, 1)
-0.2
Edit: Actually, rem is basically the same speed as mod. Both are slow. If you want fast (and you may not really care), then check out trunc, floor or ceil:
myrem1(x) = x - trunc(x) # changed name from mymod1 to myrem1
Why would you do this calculation? Except for possible floating-point issues, or imperfections of the random number generation, adding q[i-1] has no effect on the (statistical) behavior of this code: the sequences [rand() for _ in q] and [mod(x+rand(),1) for x in q] have the same distribution, regardless of the values in q (both are i.i.d. sequences of samples from the uniform distribution on (0,1)).
(Unless perhaps, you really mean to do rem rather than mod, in which case I’m still curious what the use case is. I’ve never yet seen actual use of rem where mod would be incorrect.)
That’s computing rem rather than mod
EDIT: actually, the whole thing just computes i.i.d U(0,1) values in a convoluted way. The tune() function as given can be written (up to computational issues such as imperfect RNG)
Edit: Ah, the name is bad though. Should call it myrem1.
Edit 2: Actually, there is a function in Base, called modf which does basically the same thing, and perhaps should be called remf?
help?> modf
modf(x)
Return a tuple (fpart, ipart) of the fractional and integral parts of a number. Both parts have the same sign as the
argument.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> modf(3.5)
(0.5, 3.0)
julia> modf(-3.5)
(-0.5, -3.0)
But there’s no way to distinguish between rand() and mod(q + rand(), 1) no matter what q is. They are both random variables with identical distributions, i.e. uniformly distributed between 0 and 1.
The original line was before final debugging. The correct line is:
x=transpose(abs.(2 .* mod.(collect(UnitRange(1:nv)) .* q[i-1] .+ rand(), 1) .- 1))
# note: the rand() is not broadcast -- it's a single random uniform value added to all elements
OK, previously you made a random vector, rand(nv) (well actually, you made a random matrix, rand(1, nv)), so this is different, if it’s just one single random number to the entire range.
BTW, separately from the previous point: this construct is a bit odd:
collect(UnitRange(1:nv))
So, 1:nv is already a UnitRange. Putting it in a UnitRange constructor is redundant. Then, you convert it to an Array{Int, 1} using collect. Ranges have really nice properties, so I suggest that you just write (1:nv) .* q[i-1] instead of collect(UnitRange(1:nv)) .* q[i-1].
Thanks, I was hoping you’d have some tips on this.
collect(UnitRange(1:nv)) came about because it works in the REPL. I look up how to create a sequence from 1…n – find UnitRange(). Also see that collect() explodes the range out.
Yes, after mod it cannot any longer be expressed as a range, so mod converts ranges to ordinary Array{.,1}s. Note, though, that ranges are arrays, they’re just not Arrays.
Hmmmm. I still don’t quite get why you put it inside the UnitRange call I mean, you wouldn’t write s = String("Hello!"), right? Just s = "Hello!"?