I'm trying to speed up a loop that runs for about 100000 iterations and was wondering if the order of if statements had an effect on the performance. For example will the following code check the if and elseif before executing the statements in else every time it goes through the for loop?
for ii = 1:100000
if ii == 1
statements_1;
elseif ii >= 2 && ii <= 10
statements_2;
else
statements_3;
end
end
Will the below code run faster?
for ii = 1:100000
if ii > 10
statements_3;
elseif ii >= 2 && ii <= 10
statements_2;
else
statements_1;
end
end
Any help will be much appreciated
Yes, it will check the first condition fist, and then if it is false, it will check the following conditions.
However, to improve performance, I suggest you to use a more vectorized code:
for i=find(condition1(1:10000))
statements1
end
for i=find(condition2(1:10000))
statements2
end
for i=find(condition3(1:10000))
statements3
end
with for instance condition2=#(i) (i>2 & i<10)
Related
I have an algorithm that looks like this:
10 WRITE (*,*) "Start"
DO I = 1, 10
WRITE (*,*) "Step"
IF(I .EQ. 5) then
go to 10
END IF
END DO
I want to restart the loop, when that if statement executes. However, I don't want to have to use a go to, I tried this:
10 WRITE (*,*) "Start"
DO I = 1, 10
WRITE (*,*) "Step"
IF(I .EQ. 5) then
I = 0; CYCLE
END IF
END DO
But then I get the error that I can't redefine the I variable, inside a loop. So I'm not sure how to approach this. Any help would be much appreciated
A conceptually simple way to phrase this problem is: "I want to repeat a loop until it completes, where there is some abort condition".
This "repeat until it completes" is idiomatically a do construct with indeterminate iterations:
do
... ! Our actions; we exit this outer loop when we are satisfied
end do
[This could also be phrased as a do-while loop.]
With the inner loop:
do
do i=1,10
... ! A conditional statement which aborts the inner loop
... ! And some actions
end do
! And once we're complete we exit the outer loop
end do
Now it's just a matter of handling "abort inner" and "exit outer". Here cycle and exit:
outer: do
print*, 'Start'
do i=1,10
print*, 'Step'
if (...) cycle outer ! Abort the inner loop
end do
exit outer ! The inner loop completed, so we're done
end do outer
The outer loop is labelled so that the cycle statement in the inner loop can reference it. Without that label the cycle will cycle the innermost loop containing it.
Likely a typo here somewhere, but this has some other ideas in a "do while" sense.
i.e. One could poll something coming in.
... USE ISO... etc stuff.
REAL(KIND=C_FLOAT), DIMENSION(10) :: A
LOGICAL(KIND=C_BOOL) :: Question1 = .TRUE.
LOGICAL(KIND=C_BOOL) :: Question2 = .TRUE.
INTEGER(KIND=C_INT) :: Index = 0
INTEGER(KIND=C_INT) :: I = 5
WRITE(*,*)'Enter first index to skip:"
READ(*,*) I
Outer_Loop: DO WHILE (Question1) ! .eq. .TRUE.
Inner_Loop: DO WHILE (Question2) ! .EQV. .TRUE.
Index = Index + 1
IF(Index > UBOUND(A,1)) THEN
Question1 = .FALSE.
Question2 = .FALSE.
Exit
ENDIF
IF(Index == I) EXIT
!Whatever like A(INdex) = something....
ENDDO Inner_Loop
IF(Question1) THEN !We must have more to possibly read or do...
WRITE(*,*)'Do more? 1=yes, 0=No"
READ(*,*) I
IF(I == 1) THEN
WRITE(*,*)'Enter next index to skip:"
READ(*,*) I
Question2 = .TRUE.
!and one can do a reset of I=0 here, which then becomes I=1 the next time through the inner loop...
ELSE
Question1 = .FALSE.
Question2 = .FALSE.
EXIT
ENDIF
ELSE !Must have gotten here to exit at the end of array?
EXIT
ENDIF
ENDDO Outer_Loop
I can suggest to ways of solving this issue: either use a while loop or a recursive function (highly depends on your actual algorithm). I am attaching a sample code for both cases (keep in mind that having variables with save qualifier is not the best idea, it's much better to do that with by passing variables as arguments to function - here it is used just for simplicity)
module functions
implicit none
integer :: restarted, save = 0
contains
recursive subroutine restart_loop
integer :: i
do i = 1, 10
print*, i
if ( i == 5 .and. restarted < 5 ) then
restarted = restarted + 1
call restart_loop
exit
end if
end do
end subroutine restart_loop
subroutine while_loop
integer :: i = 1
do while (i <= 10)
print*, i
if ( i == 5 .and. restarted < 5 ) then
i = 1
restarted = restarted + 1
end if
i = i + 1
end do
end subroutine while_loop
end module functions
program test_prog
use functions
implicit none
call while_loop
end program test_prog
I'm trying to implement Smith-Waterman alignment in parallel using Julia (see: Figure 1 of http://www.cs.virginia.edu/~rl6sf/paper_dump/2011:12:33:22.pdf), but the algorithm is running much slower in Julia than the serial version. I'm using shared arrays to do this and figure I am doing something silly that is making the code run slow. Could someone take a look and see if my code is optimized as possible? The parallel version should run faster than in serial….
The basic concept of it is to compute the anti-diagonal elements of a matrix in parallel from the upper left to lower right corner and to update them. I'm trying to use 32 cores on a shared array machine to do this. I have a SharedArray matrix that I am using to do this and am computing the elements of each anti-diagonal in parallel as shown below. The while loops in the spSW function submit tasks to workers in sync for each anti-diagonal using the helper function shared_get_score(). The main goal of this function is to fill in each element in the shared arrays "matrix" and "path".
function spSW(seq1,seq2,p)
indel = -1
match = 2
seq1 = "^$seq1"
seq2 = "^$seq2"
col = length(seq1)
row = length(seq2)
wl = workers()
matrix,path = shared_initialize_path(seq1,seq2)
for j = 2:col
jcol = j
irow = 2
#sync begin
count = 0
while jcol > 1 && irow < row + 1
#println(j," ",irow," ",jcol)
if seq1[jcol] == seq2[irow]
equal = true
else
equal = false
end
w = wl[(count % p) + 1]
#async remotecall_wait(w,shared_get_score!,matrix,path,equal,indel,match,irow,jcol)
jcol -= 1
irow += 1
count += 1
end
end
end
for i = 3:row
jcol = col
irow = i
#sync begin
count = 0
while irow < row+1 && jcol > 1
#println(j," ",irow," ",jcol)
if seq1[jcol] == seq2[irow]
equal = true
else
equal = false
end
w = wl[(count % p) + 1]
#async remotecall_wait(w,shared_get_score!,matrix,path,equal,indel,match,irow,jcol)
jcol -= 1
irow += 1
count += 1
end
end
end
return matrix,path
end
The other helper functions are:
function shared_initialize_path(seq1,seq2)
col = length(seq1)
row = length(seq2)
matrix = convert(SharedArray,fill(0,(row,col)))
path = convert(SharedArray,fill(0,(row,col)))
return matrix,path
end
#everywhere function shared_get_score!(matrix,path,equal,indel,match,i,j)
pathvalscode = ["-","|","M"]
pathvals = [1,2,3]
scores = []
push!(scores,matrix[i,j-1]+indel)
push!(scores,matrix[i-1,j]+indel)
if equal
push!(scores,matrix[i-1,j-1]+match)
else
push!(scores,matrix[i-1,j-1]+indel)
end
val,ind = findmax(scores)
if val < 0
matrix[i,j] = 0
else
matrix[i,j] = val
end
path[i,j] = pathvals[ind]
end
Does anyone see an obvious way to make this run faster? Right now it's about 10 times slower than the serial version.
I'm learning Ruby On Rails program and I've came to a road block on one of the lessons. The assignment has me creating an odd numbers for the script to read starting from "20 to 0" using the next component. This is the example they've given me to change :
i = 20
loop do
i -= 1
print "#{i}"
break if i <= 0
end
This is the problem:
Add a line to your loop before your print statement. Use the next keyword so that you skip to the next iteration if the number i is odd.
How do I accomplish this?
You can just insert a next that skips the rest of the loop if the number is odd:
i = 20
loop do
i -= 1
next if i.odd?
puts "#{i}"
break if i <= 0
end
I would solve it this way:
i = 20
loop do
i -= 1
next if i%2 != 0
print "#{i}"
break if i <= 0
end
i = 20
loop do
i -= 1
next if i % 2 == 0
print "#{i}"
break if i <=1
end
Basically I am trying to solve a 2nd order differential equation with the forward euler method. I have some for loops inside my code, which take considerable time to solve and I would like to speed things up a bit. Does anyone have any suggestions how could I do this?
And also when looking at the time it takes, I notice that my end at line 14 takes 45 % of my total time. What is end actually doing and why is it taking so much time?
Here is my simplified code:
t = 0:0.01:100;
dt = t(2)-t(1);
B = 3.5 * t;
F0 = 2 * t;
BB=zeros(1,length(t)); % Preallocation
x = 2; % Initial value
u = 0; % Initial value
for ii = 1:length(t)
for kk = 1:ii
BB(ii) = BB(ii) + B(kk) * u(ii-kk+1)*dt; % This line takes the most time
end % This end takes 45% of the other time
x(ii+1) = x(ii) + dt*u(ii);
u(ii+1) = u(ii) + dt * (F0(ii) - BB(ii));
end
Running the code it takes me 8.552 sec.
You can remove the inner loop, I think:
for ii = 1:length(t)
for kk = 1:ii
BB(ii) = BB(ii) + B(kk) * u(ii-kk+1)*dt; % This line takes the most time
end % This end takes 45% of the other time
x(ii+1) = x(ii) + dt*u(ii);
u(ii+1) = u(ii) + dt * (F0(ii) - BB(ii));
end
So BB(ii) = BB(ii) (zero at initalisation) + sum for 1 to ii of BB(kk)* u(ii-kk+1).dt
but kk = 1:ii, so for a given ii, ii-kk+1 → ii-(1:ii) + 1 → ii:-1:1
So I think this is equivalent to:
for ii = 1:length(t)
BB(ii) = sum(B(1:ii).*u(ii:-1:1)*dt);
x(ii+1) = x(ii) + dt*u(ii);
u(ii+1) = u(ii) + dt * (F0(ii) - BB(ii));
end
It doesn't take as long as 8 seconds for me using either method, but the version with only one loop is about 2x as fast (the output of BB appears to be the same).
Is the sum loop of B(kk) * u(ii-kk+1) just conv(B(1:ii),u(1:ii),'same')
The best way to speed up loops in matlab is to try to avoid them. Try if you are able to perform a matrix operation instead of the inner loop. For example try to break the calculation you do there in small parts, then decide, if there are parts you can perform in advance without knowing the results of the next iteration of the loop.
to your secound part of the question, my guess:: The end contains the check if the loop runs for another round and this check by it self is not that long but called 50.015.001 times!
This loop does not terminate after I type x. I'm really new to Ruby, and so far, it is so much different than what I learned before - quite interesting,
total = 0
i = 0
while ((number = gets) != "x")
total += number.to_i
i += 1
end
puts "\nAverage: " + (total / i).to_s
Any help is greatly appreciated.
Because gets gives you the newline as well. You need to chomp it.
Try:
while ((number = gets.chomp) != "x")
and you'll see it starts working:
pax> ruby testprog.rb
1
5
33
x
Average: 13