QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: MrFreyer on June 05, 2019, 09:56:03 am

Title: FOR i = 1 TO 0 is slow?
Post by: MrFreyer on June 05, 2019, 09:56:03 am
Hi everyone,

I have a performance question about canceled FOR...NEXT loops.

Is this a bad and slow method of programming?
Code: QB64: [Select]
  1. quantity = 0
  2.  
  3. FOR i = 1 TO quantity
  4. '...


...and would this be a faster method?
Code: QB64: [Select]
  1. quantity = 0
  2.  
  3. IF quantity > 0 THEN
  4. FOR i = 1 TO quantity
  5. '...

Thanks!
Title: Re: FOR i = 1 TO 0 is slow?
Post by: RhoSigma on June 05, 2019, 10:33:10 am
No difference, if "quantity" is already less than the loop's start counter, then the loop will never be executed, but is skipped immediatly. The program proceeds with the line following the NEXT statement. However if "quantity" is greater than the start counter, then you only would add another (useless) check with the IF...THEN block, hence you are slower with your second example.
Title: Re: FOR i = 1 TO 0 is slow?
Post by: Ashish on June 05, 2019, 10:36:24 am
It depends on what you intended to do.
Code: QB64: [Select]
  1. FOR i = 1 to 0
  2. '...
  3.  
It becomes a infinity type loop. It will continue forever unless you quit the program. If your intention was to move from 1 to 0 in a FOR NEXT loop
then you need to mention the STEP.
This will work -
Code: QB64: [Select]
  1. FOR i = 1 to 0 STEP -1
  2. '...
  3.  
EDIT : Oops. Sorry. This type of loop get skipped in BASIC. Hey, but in other like C++, it does become a forever loop.
Title: Re: FOR i = 1 TO 0 is slow?
Post by: bplus on June 05, 2019, 11:58:46 am
FOR ...NEXT is slow loop structure, WHILE ...WEND or DO ...LOOP are faster, of course you have to code exit to avoid infinite loop.
Title: Re: FOR i = 1 TO 0 is slow?
Post by: MrFreyer on June 05, 2019, 01:15:02 pm
No difference, if "quantity" is already less than the loop's start counter, then the loop will never be executed, but is skipped immediatly. The program proceeds with the line following the NEXT statement. However if "quantity" is greater than the start counter, then you only would add another (useless) check with the IF...THEN block, hence you are slower with your second example.
Okay thanks, good to know.

FOR ...NEXT is slow loop structure, WHILE ...WEND or DO ...LOOP are faster, of course you have to code exit to avoid infinite loop.
So I should never use FOR...NEXT loops? Just DO...LOOPs with an counter as exit condition? Do you know why DO...LOOPs are faster?
I've read that SELECT CASE should also be faster than IF...THEN...ELSEIF (in some cases...). That's also correct?
Title: Re: FOR i = 1 TO 0 is slow?
Post by: bplus on June 05, 2019, 02:30:31 pm
I only mention this if you really need every boost you can get:
Code: QB64: [Select]
  1. PRINT "Running 4 timed tests please wait..."
  2.  
  3. n = 1000000000
  4.  
  5. t! = TIMER
  6. x = 0: i = 0
  7. doloop:
  8. i = i + 1
  9. x = x + i
  10. IF i < n THEN GOTO doloop
  11. t2! = TIMER
  12.  
  13. x = 0: i = 0
  14. WHILE i < n
  15.     i = i + 1
  16.     x = x + i
  17. t3! = TIMER
  18.  
  19. x = 0
  20. FOR i = 0 TO n
  21.     x = x + i
  22. t4! = TIMER
  23.  
  24.  
  25. x = 0: i = 0
  26.     i = i + 1
  27.     x = x + i
  28. LOOP UNTIL i = n
  29. t5! = TIMER
  30.  
  31. PRINT n; "    times adding in Do... LOOP time is "; t5! - t4!
  32. PRINT n; "   times adding in FOR... NEXT time is "; t4! - t3!
  33. PRINT n; " times adding in While... Wend time is "; t3! - t2!
  34. PRINT n; "     times adding in GOTO loop time is "; t2! - t!
  35.  
  36.  

Here are my results in Windows 10 laptop, core i5
  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: FOR i = 1 TO 0 is slow?
Post by: SMcNeill on June 05, 2019, 03:09:27 pm
DO...LOOP is, indeed, faster than FOR...NEXT statements.

The reason is mainly because of error checking and optional parameters need with FOR.

FOR variable = Start TO Finish STEP value

With the above, the translated C-code does several checks before running.  Is value zero?  Is it less than zero?  Greater than?

If value is less than zero (counting down, like from 10 to 1), then we need to repeat the incremental loop until variable is LESS THAN Finish.  If value is greater than zero, we repeat until GREATER THAN finish...

It’s extra decision making which the translated code runs, which a DO...LOOP structure doesn’t have.  Add in error checking, and it just increases the extra steps going on under the hood with FOR loops.

*******************

For optimized speed, use DO instead of FOR.  When speed isn’t such a concern, use FOR for easy of readability and speed coding.

At least, that’s how I recommend them with QB64.
Title: Re: FOR i = 1 TO 0 is slow?
Post by: MrFreyer on June 05, 2019, 04:36:37 pm
i don't know... :D
Title: Re: FOR i = 1 TO 0 is slow?
Post by: bplus on June 05, 2019, 08:20:39 pm
Hi McFreyer,

:D  I have to ask, what OS and computer are you using? What version of QB64? 
Title: Re: FOR i = 1 TO 0 is slow?
Post by: Cobalt on June 05, 2019, 10:40:53 pm
Run from my laptop with Vista I get rather random results from run to run.
but I think his computer is still better than mine.
Title: Re: FOR i = 1 TO 0 is slow?
Post by: SMcNeill on June 05, 2019, 11:32:34 pm
Let's take a moment to look at how our QB64 code translates into C-code.

First, let's start with a simple FOR...NEXT loop:

Code: QB64: [Select]
  1. FOR i = 0 TO 100

Now, we can't get any simpler than this, and even this simple little batch of code turns into the following:

Code: [Select]
S_1:;
fornext_value2= 0 ;
fornext_finalvalue2= 100 ;
fornext_step2= 1 ;
if (fornext_step2<0) fornext_step_negative2=1; else fornext_step_negative2=0;
if (new_error) goto fornext_error2;
goto fornext_entrylabel2;
while(1){
fornext_value2=fornext_step2+(*__SINGLE_I);
fornext_entrylabel2:
*__SINGLE_I=fornext_value2;
if (fornext_step_negative2){
if (fornext_value2<fornext_finalvalue2) break;
}else{
if (fornext_value2>fornext_finalvalue2) break;
}
fornext_error2:;
if(qbevent){evnt(1);if(r)goto S_1;}
fornext_continue_1:;
}
fornext_exit_1:;

As you can see, there's quite a bit of error checking and conditioning checking going on in the code.  Each time the code runs, we have to check to see if the fornext_step_negative2 is negative or not, and then we check to see if our current value is greater (or lesser) than the final value. 

Now, let's compare this code to how a DO...LOOP is translated.  First, let's start with the QB64 code:

Code: QB64: [Select]
  1. i = 0
  2.     i = i + 1
  3. LOOP UNTIL i > 100

And the translation to this simple DO...LOOP code:

Code: [Select]
do{
*__SINGLE_I= 0 ;
if(!qbevent)break;evnt(1);}while(r);
S_2:;
do{
if(qbevent){evnt(2);if(r)goto S_2;}
do{
*__SINGLE_I=*__SINGLE_I+ 1 ;
if(!qbevent)break;evnt(3);}while(r);
S_4:;
dl_continue_1:;
}while((!(-(*__SINGLE_I> 100 )))&&(!new_error));
dl_exit_1:;
if(qbevent){evnt(4);if(r)goto S_4;}

As you can see, there's a lot fewer IF checks going in inside the DO..LOOP, as we don't need to check to see if we're counting up or down with the command.  Those checks are dependent on the user to code what's proper for their needs.

**************************

And, if we turn the checking off, like in the following code, it's even easier to see exactly how large a difference there is in the two processes.

Code: QB64: [Select]
  1. i = 0
  2.     i = i + 1
  3. LOOP UNTIL i > 100
  4.  

With checking off, the above code translates into a very simple little:
Code: [Select]
*__SINGLE_I= 0 ;
do{
*__SINGLE_I=*__SINGLE_I+ 1 ;
dl_continue_1:;
}while((!(-(*__SINGLE_I> 100 )))&&(!new_error));
dl_exit_1:;

And, if we do the same with the FOR..NEXT loop, what we see is the following:

Code: QB64: [Select]

Which translates to:

Code: [Select]
fornext_value2= 0 ;
fornext_finalvalue2= 100 ;
fornext_step2= 1 ;
if (fornext_step2<0) fornext_step_negative2=1; else fornext_step_negative2=0;
if (new_error) goto fornext_error2;
goto fornext_entrylabel2;
while(1){
fornext_value2=fornext_step2+(*__SINGLE_I);
fornext_entrylabel2:
*__SINGLE_I=fornext_value2;
if (fornext_step_negative2){
if (fornext_value2<fornext_finalvalue2) break;
}else{
if (fornext_value2>fornext_finalvalue2) break;
}
fornext_error2:;
fornext_continue_1:;
}
fornext_exit_1:;

Which, once we compare the two routines closely against each other, easily (in my opinion) showcases why the DO...LOOP structure is inherently faster than the FOR...NEXT translation.

************************

As to why some people are seeing faster times with the FOR..NEXT, over the DO...LOOP, I have no idea what's going on.  Logic tells us that it's going to be faster to simply add a value to a number, than it is to add a value to a number and then check to see if it's counting up or down...  DO simply has fewer steps to its process than FOR does. 

Out of curiosity, could you guys who are seeing the faster FOR loops add the $CHECKING:OFF command to Bplus's code and then run it.  I'm curious how much of a delay the internal error checking processes are making on the code.

Tr this, and see how it performs for you folks:

Code: QB64: [Select]
  1. PRINT "Running 4 timed tests please wait..."
  2.  
  3. n = 1000000000
  4.  
  5. t! = TIMER
  6. x = 0: i = 0
  7. doloop:
  8. i = i + 1
  9. x = x + i
  10. IF i < n THEN GOTO doloop
  11. t2! = TIMER
  12.  
  13. x = 0: i = 0
  14. WHILE i < n
  15.     i = i + 1
  16.     x = x + i
  17. t3! = TIMER
  18.  
  19. x = 0
  20. FOR i = 0 TO n
  21.     x = x + i
  22. t4! = TIMER
  23.  
  24.  
  25. x = 0: i = 0
  26.     i = i + 1
  27.     x = x + i
  28. LOOP UNTIL i = n
  29. t5! = TIMER
  30.  
  31. PRINT n; "    times adding in Do... LOOP time is "; t5! - t4!
  32. PRINT n; "   times adding in FOR... NEXT time is "; t4! - t3!
  33. PRINT n; " times adding in While... Wend time is "; t3! - t2!
  34. PRINT n; "     times adding in GOTO loop time is "; t2! - t!
  35.  
Title: Re: FOR i = 1 TO 0 is slow?
Post by: RhoSigma on June 06, 2019, 01:46:38 am
I'm still wondering, why the FOR...NEXT loop has such a bulky (goto label) implementation from QB64 -> C++ level. Wouldn't it be better simply translated into a C++ "for" loop?

Using "goto" in C++ is even more frowned upon than some people already do in BASIC.

counting up:
Code: C: [Select]
  1. for (int i = 0; i <= 100; i++) {
  2.     // do stuff here;
  3. }

counting down:
Code: C: [Select]
  1. for (int i = 100; i >= 0; i--) {
  2.     // do stuff here;
  3. }

or given a STEP (eg. 5):
Code: C: [Select]
  1. for (int i = 0; i <= 100; i+=5) {
  2.     // do stuff here;
  3. }
Title: Re: FOR i = 1 TO 0 is slow?
Post by: SMcNeill on June 06, 2019, 02:44:33 am
I'm still wondering, why the FOR...NEXT loop has such a bulky (goto label) implementation from QB64 -> C++ level. Wouldn't it be better simply translated into a C++ "for" loop?

Only Galleon knows why he translated some of the commands the way he has.  After all, I also wonder, why does a FOR loop need a temp variable?

Code: [Select]
fornext_value2=fornext_step2+(*__SINGLE_I);
fornext_entrylabel2:
*__SINGLE_I=fornext_value2;

Why not simply let the variable equal the value naturally?  Reduce a few assignment processes each loop.  Why not just a simple:

__SINGLE_I = __SINGLE_I + fornext_step2;

Title: Re: FOR i = 1 TO 0 is slow?
Post by: MrFreyer on June 06, 2019, 05:03:29 am
Hi McFreyer,

:D  I have to ask, what OS and computer are you using? What version of QB64?
Windows 10 Laptop, Intel Celeron 2.16GHz, 4GB RAM
QB64 v0.954
I will download the latest version now...

Let's take a moment to look at how our QB64 code translates into C-code.
Thanks for the insight!!!!

EDIT:
the 1.3 version (64 bit) was faster, from 10.6 sec (FOR...NEXT) till 11.9 sec (DO...LOOP)
the FOR...NEXT loop was still the fastest...
Title: Re: FOR i = 1 TO 0 is slow?
Post by: bplus on June 06, 2019, 09:28:56 am
Windows 10 Laptop, Intel Celeron 2.16GHz, 4GB RAM
QB64 v0.954
I will download the latest version now...
Thanks for the insight!!!!

EDIT:
the 1.3 version (64 bit) was faster, from 10.6 sec (FOR...NEXT) till 11.9 sec (DO...LOOP)
the FOR...NEXT loop was still the fastest...

Wow such unexpected (by me at least) results.

Quote
Can Celeron processor support Windows 10?
For processing, Windows 10 requires a CPU with a minimum speed of 1GHz. This is a very low bar to clear, as even Intel's low-powered Atom and Celeron processors have been above the 1GHz mark for several years. ... You'll also want to look up whether or not your processor supports a 64-bit operating system.Oct 17, 2017

Well it must support 64 bit or it couldn't run QB64 v1.3 64 bit for Windows, I imagine.

I am interested also in results Steve requested from folks whose FOR ...NEXT loop is running faster than others:
Let's take a moment to look at how our QB64 code translates into C-code.

First, let's start with a simple FOR...NEXT loop:

...

Out of curiosity, could you guys who are seeing the faster FOR loops add the $CHECKING:OFF command to Bplus's code and then run it.  I'm curious how much of a delay the internal error checking processes are making on the code.

Tr this, and see how it performs for you folks:

Code: QB64: [Select]
  1. PRINT "Running 4 timed tests please wait..."
  2.  
  3. n = 1000000000
  4.  
  5. t! = TIMER
  6. x = 0: i = 0
  7. doloop:
  8. i = i + 1
  9. x = x + i
  10. IF i < n THEN GOTO doloop
  11. t2! = TIMER
  12.  
  13. x = 0: i = 0
  14. WHILE i < n
  15.     i = i + 1
  16.     x = x + i
  17. t3! = TIMER
  18.  
  19. x = 0
  20. FOR i = 0 TO n
  21.     x = x + i
  22. t4! = TIMER
  23.  
  24.  
  25. x = 0: i = 0
  26.     i = i + 1
  27.     x = x + i
  28. LOOP UNTIL i = n
  29. t5! = TIMER
  30.  
  31. PRINT n; "    times adding in Do... LOOP time is "; t5! - t4!
  32. PRINT n; "   times adding in FOR... NEXT time is "; t4! - t3!
  33. PRINT n; " times adding in While... Wend time is "; t3! - t2!
  34. PRINT n; "     times adding in GOTO loop time is "; t2! - t!
  35.  
Title: Re: FOR i = 1 TO 0 is slow?
Post by: Cobalt on June 06, 2019, 11:07:11 am
running on my desktop, also VISTA get more consistant times, but GOTO becomes the fastest and While\Wend the slowest!!(see image)
(both these machines are using an INTEL processor)

with Steve's checking off version, everything gets ~1.5secs faster except for\next which stays nearly the same. GOTO(3.90) comes in first, then DO\Loop(4.23) then WHILE\Wend(4.33) and last is for\next(5.27).

running everything a LONG instead of _INTEGER64 knocks nearly another second+ off(save for\next). GOTO still wins(2.58), fallowed by WHILE\WEND(2.91), then DO\LOOP(2.96) and last FOR\NEXT(5.38)
Title: Re: FOR i = 1 TO 0 is slow?
Post by: SMcNeill on June 06, 2019, 11:22:40 am
running on my desktop, also VISTA get more consistant times, but GOTO becomes the fastest and While\Wend the slowest!!

From the numbers you posted, don’t you mean FOR..NEXT was the slowest?
Title: Re: FOR i = 1 TO 0 is slow?
Post by: Cobalt on June 06, 2019, 11:30:00 am
From the numbers you posted, don’t you mean FOR..NEXT was the slowest?

look at the image of the 4 runs I performed on B+ code. I didn't do screenshots of the last runs where I used your CHECKING: OFF code.
Title: Re: FOR i = 1 TO 0 is slow?
Post by: bplus on June 06, 2019, 12:37:57 pm
I find it extremely interesting that Colbalt gets best times from GOTO, that was what I originally wanted to test when I compared to WHILE ...WEND structure before adding on all the other loop structures with mods.
Title: Re: FOR i = 1 TO 0 is slow?
Post by: Cobalt on June 07, 2019, 01:19:19 am

... s(2.58), fallowed by WHILE\WEND(2.91), th ...
been looking up info on fallow deer too much! :D
Ah well.

I have to say that maybe the for\next routines need rewritten. I was going to 'hack' the MAIN.TXT in the temp folder to see if I could get better time from for\next, but i couldn't figure out just how the for\next was actually being handled, cause I don't see anything that resembles an actual FOR statement it in the code. I was curious just how a standard for\next loop would stack up if I just hard coded in the C++ code. I wonder if there is some weird nuance in QB45's for\next that Galleon was trying to account for by translating it this way? or maybe he was just stoned when he wrote it?
Title: Re: FOR i = 1 TO 0 is slow?
Post by: TempodiBasic on June 07, 2019, 04:58:56 am
Hi Guys
here my feedback on Windows10 and QB64 1.3

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

about TRANSlation in QBASIC to C++ I think that there is an Option in Google Translation, but I think we get more another version

Title: Re: FOR i = 1 TO 0 is slow?
Post by: RhoSigma on June 07, 2019, 05:53:29 am
????? Google can translate BASIC into C++ ?????

How??
Title: Re: FOR i = 1 TO 0 is slow?
Post by: TempodiBasic on June 07, 2019, 01:39:56 pm
Really?
see here what say google when you type translate BASIC to C...

https://www.google.it/search?source=hp&ei=rpz6XNm5H6_isAfupIrAAg&q=translate+BASIC+to+C&oq=translate+BASIC+to+C&gs_l=psy-ab.12..33i22i29i30l10.2379.2379..7658...0.0..0.456.456.4-1......0....2j1..gws-wiz.....0.VIio-WwhkpM (https://www.google.it/search?source=hp&ei=rpz6XNm5H6_isAfupIrAAg&q=translate+BASIC+to+C&oq=translate+BASIC+to+C&gs_l=psy-ab.12..33i22i29i30l10.2379.2379..7658...0.0..0.456.456.4-1......0....2j1..gws-wiz.....0.VIio-WwhkpM)

However, going out of joke , I have no technical knowdledge to show you what is needed to translate from a High Level language to Another High Level language...
I can imagine that the path is the same for BASIC and C compiled,
BASIC-->Assembler of BASIC compiler and libraries-->CodeMachine
C-->Assembler of C compiler and libraries--> CodeMachine
So you can easly translate from BASIC to C in the manner C has structures similar to those of  BASIC or can emulate those of BASIC...

How a compiler can make cross platform executable, I don't know and I ignore also if GCC o g++ can do this kind of performance.

PS I have found this affirmation that scares me
https://quotefancy.com/quote/1164258/Edsger-W-Dijkstra-Programming-in-Basic-causes-brain-damage (https://quotefancy.com/quote/1164258/Edsger-W-Dijkstra-Programming-in-Basic-causes-brain-damage)

Title: Re: FOR i = 1 TO 0 is slow?
Post by: RhoSigma on June 07, 2019, 03:39:05 pm
Ah, i see, these are search results for diverse code convertors.

I was curios about, because you mentioned and option in "Google Translate", but maybe i got that wrong.

On the other side, it would be cool, if there were a way translating between programming languages using "Google Translate" just like it works for real spoken languages. Maybe we should suggest this as an enhancement to the Google Support board :)
Title: Re: FOR i = 1 TO 0 is slow?
Post by: TempodiBasic on June 07, 2019, 08:13:28 pm
Quote
I was curios about, because you mentioned and option in "Google Translate", but maybe i got that wrong.

That was a joke of mine but I ignore if there is an underground option of Google Translate!
:-)
Title: Re: FOR i = 1 TO 0 is slow?
Post by: SW on June 11, 2019, 11:57:01 pm
Win7 SP1 on i7 2600
 [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: FOR i = 1 TO 0 is slow?
Post by: Raven_Singularity on June 12, 2019, 09:48:35 am
You said the times were fairly random each run.  This suggests that something is probably using your CPU (other apps or background services running), or something is causing delays (anti-malware/anti-virus apps, etc.).

Check your Task Manager to ensure your CPU is steady at 0% before you run the test, and ensure your virus/malware apps whitelist/ignore QB64.