Oberon Community Platform Forum
December 12, 2019, 09:28:41 AM *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
News:
 
   Home   Help Search Login Register  
Pages: [1]
  Print  
Author Topic: FOR loop  (Read 8467 times)
BohdanT
Sr. Member
****
Posts: 271


Life is difficult, but fortunately is short!


WWW
« on: October 29, 2009, 12:55:39 PM »

Hi All!

there is a problem in the loop "FOR" in the case:
FOR i: = startval TO MAX(anytype) DO

In this case cycle - infinite loop.
This is due to the fact that the condition for breaking the cycle is exceeds value is specified in the "TO" (is impossible).

for example in case SMALLINT:
VAR
   i:SMALLINT;
BEGIN
   FOR i:=startval TO MAX(SMALLINT) DO END
END;

before loop:
Code:
PUSH 32767

at the begin of loop:
Code:
MOV BX, -2[EBP] b: -2[EBP]
CMP BX, 0[ESP]
JNLE 55 (000000B4H)
in this case, the condition will never be executed.
Because the maximum number of 32767 and there is no number greater than it

   
To solve this problem сan be make, as did, for example, in FPC

Code:
CMP [startval],stopval
JG exit ;JNG
DEC [startval]

loop:
INC [startval]
...
...
...
CMP [startval],stopval
JL loop ;JNL
exit:
Logged
cfbsoftware
Full Member
***
Posts: 107


WWW
« Reply #1 on: October 30, 2009, 12:30:20 AM »


there is a problem in the loop "FOR" in the case:

Code:
FOR i: = startval TO MAX(anytype) DO

In this case cycle - infinite loop.
This is due to the fact that the condition for breaking the cycle is exceeds value is specified in the "TO" (is impossible).

for example in case SMALLINT:

Code:
VAR
i:SMALLINT;
BEGIN
FOR i:=startval TO MAX(SMALLINT) DO END
END;



Refer to the Oberon Language Report. This is a consequence of the definition of the FOR loop in Oberon:

Code:
   FOR v := beg TO end BY step DO statements END

is equivalent to

Code:
  temp := end; v := beg;
  IF step > 0 THEN
    WHILE v <= temp DO statements; v := v + step END
  ELSE
    WHILE v >= temp DO statements; v := v + step END
  END


If range-checking is enabled the example should result in a runtime error. If range-checking is not enabled, typically the final v := v + step wraps around to MIN(v) and an infinite loop is the result.

To handle cases like this you need to either:

Make sure that the FOR loop counter is a wider type than the upper-limit:

Code:
VAR
  i: INTEGER;
BEGIN
  FOR i := startval TO MAX(SMALLINT) DO END
END;


or reformulate as a WHILE or REPEAT loop.

While this issue is a nuisance if you are not aware of it, in practice it occurs highly infrequently. It is one of those mistakes that you should find that you only make once  Wink

Logged

Chris Burrows
Astrobe v7.0 (Feb 2019): Oberon for ARM Cortex-M3, M4 and M7 Microcontrollers
http://www.astrobe.com
BohdanT
Sr. Member
****
Posts: 271


Life is difficult, but fortunately is short!


WWW
« Reply #2 on: October 30, 2009, 08:55:08 AM »

Quote
Refer to the Oberon Language Report. This is a consequence of the definition of the FOR loop in Oberon:
I must admit that you are right!

However, the bad, it is necessary to dig in the documentation.
Since directly this information in the ActiveOberon language report - absent. We have to look for Oberon-2 language report.  Sad
Logged
BohdanT
Sr. Member
****
Posts: 271


Life is difficult, but fortunately is short!


WWW
« Reply #3 on: November 04, 2009, 04:17:51 PM »

Quote
If range-checking is enabled the example should result in a runtime error. If range-checking is not enabled, typically the final v := v + step wraps around to MIN(v) and an infinite loop is the result.

How to enable range-checking?

Code:
(** code generator options *)
ArrayCheck* = 0; (* x - perform array boundary checks *)
OverflowCheck* = 1; (* v - perform overflow check *)
NilCheck* = 2; (* N - explicit hard-coded nil checks *)
TypeCheck*= 3; (* t - perform type checks *)
PtrInit* = 5; (* p - initialize pointers to NIL *)
AssertCheck* = 6; (* a - evaluate asserts *)
Optimize* = 13;
FullStackInit* = 20; (* z - clear all values on stack *)
AlignedStack*=21; (* A - generate code with stack alignment for unix Aos *)

ExportDefinitions* = 30;
UseDefinitions* = 31;

(** parser options *)
NewSF* = 16; (* s - generation of new symbol file allowed *)
ExtSF* = 17; (* e - generation of extended symbol file allowed *)
Breakpoint* = 18; (* f - find position in code *)
CacheImports* = 19; (* c - Cache imported modules *)
NoFiles* = 21; (* n - don't generate files, parse only*)
NoOpOverloading* = 22; (* o - do NOT allow operator overloading *)
BigEndian* = 23; (* b - generate big endian code, makes only sense together with ARM backend *)
Warnings* = 24; (* W - display warnings *)
SkipOldSFImport* = 25; (* S - skip old symbol file import in PCOM.Export, avoids compiler error when migrating to new object file *) (* ug *)
MultipleModules*= 26; (* M - allow compilation of multiple modules within one file *)

   

I did not notice the changes:
Code:
MODULE ovr;
PROCEDURE Do*;
   VAR
   i:INTEGER;
BEGIN
   FOR i:=0 TO MAX(INTEGER) DO END
END Do;

END ovr.Do;
PC.Compile \v ovr.Mod~

Quote
While this issue is a nuisance if you are not aware of it, in practice it occurs highly infrequently. It is one of those mistakes that you should find that you only make once

disagree.
Let me and you know about it, and who does not know.
And generally I do not understand why done so and not otherwise.
It is illogical as that!
Logged
cfbsoftware
Full Member
***
Posts: 107


WWW
« Reply #4 on: November 05, 2009, 01:25:45 AM »

How to enable range-checking?

range-checking <--> overflow / underflow checking:

Code:
(** code generator options *)
OverflowCheck* = 1; (* v - perform overflow check *)

   
Quote
I did not notice the changes:
Code:

MODULE ovr;
PROCEDURE Do*;
   VAR
   i:INTEGER;
BEGIN
   FOR i:=0 TO MAX(INTEGER) DO END
END Do;

END ovr.Do;

PC.Compile \v ovr.Mod~

The line
Code:
END ovr.Do;
is suspicious but it may just have compiled up to the period and ignored the rest.

Perhaps you didn't free the older version before running the new one?

Perhaps overflow checking is not working properly but I doubt it.

I tested your code on the Windows version of ETH Oberon-2 with Active Oberon extensions. Running without overflow checks resulted in an infinite loop as expected. Running after compiling with the \v option resulted in the runtime error:

Code:
TRAP integer overflow in thread Oberon.Loop

ovr.Do  PC = 34
i = 32767


Quote
And generally I do not understand why done so and not otherwise.
It is illogical as that!

Language design inevitably involves trade-offs and risk-assessment. Unfortunately, some issues are not clearly black or white. As an exercise to highlight the trade-offs involved here, do the following:

1. Reformulate the FOR loop as a WHILE loop with the necessary checks to prevent overflow and underflow ever happening.
2. Compare the efficiency of your reformulation with the original WHILE-based definition of the FOR loop
3. Estimate the proportion of times in real-world applications that the upper-limit / lower-limit of the FOR loop is likely to overflow / underflow compared to the number of times it is not. Make sure that you take into account that the primary recommended usage of the FOR loop is to initialise ARRAYs.
4. Consider whether the additional overhead of (2) that would be incurred in every instance of FOR loops is justified simply to avoid the risk estimated in (3).

If you want to identify problems such as these at the earliest possible opportunity always enable the most defensive set of compilation options i.e. array boundary checks on, overflow checking on, Nil check on, optimisation off etc. etc. Only disable any of them (and then only as locally as necessary) if and when profiling has identified specific performance bottlenecks.
« Last Edit: November 05, 2009, 01:27:36 AM by cfbsoftware » Logged

Chris Burrows
Astrobe v7.0 (Feb 2019): Oberon for ARM Cortex-M3, M4 and M7 Microcontrollers
http://www.astrobe.com
BohdanT
Sr. Member
****
Posts: 271


Life is difficult, but fortunately is short!


WWW
« Reply #5 on: November 05, 2009, 04:06:22 PM »

Quote
Perhaps you didn't free the older version before running the new one?
I'll understand a little bit like a button press.
I have not seen changes in the code, if the option OverflowCheck ON.

Quote
Language design inevitably involves trade-offs and risk-assessment. Unfortunately, some issues are not clearly black or white. As an exercise to highlight the trade-offs involved here, do the following:
   
In my example, before a cycle test, and no difference.
    
The main difference in the value of the variable-cycle, after the end of the cycle.
But I do not think it is right to expect at what you value. For this there WHILE.

FOR - it is a simple cycle, which should work like a Swiss watch  Cheesy
Logged
BohdanT
Sr. Member
****
Posts: 271


Life is difficult, but fortunately is short!


WWW
« Reply #6 on: November 05, 2009, 04:13:30 PM »

Quote
Make sure that you take into account that the primary recommended usage of the FOR loop is to initialise ARRAYs.
Machine.Fill - faster
Logged
cfbsoftware
Full Member
***
Posts: 107


WWW
« Reply #7 on: November 06, 2009, 12:53:04 AM »

Quote
Make sure that you take into account that the primary recommended usage of the FOR loop is to initialise ARRAYs.
Machine.Fill - faster
Not Oberon. Not portable. Not equivalent in general e.g.
Code:
tens[0] := 1.0;
FOR i := 1 TO LEN(tens) - 1 DO tens[i] := tens[i-1] * 10.0 END
Logged

Chris Burrows
Astrobe v7.0 (Feb 2019): Oberon for ARM Cortex-M3, M4 and M7 Microcontrollers
http://www.astrobe.com
BohdanT
Sr. Member
****
Posts: 271


Life is difficult, but fortunately is short!


WWW
« Reply #8 on: November 06, 2009, 11:40:46 AM »

Quote
Not Oberon. Not portable. Not equivalent in general e.g.
it was a joke.
Bad that branch A2 under the ARM-processor is now destroyed.

And the example that you have, it is better to put them in constants.
« Last Edit: November 06, 2009, 11:44:12 AM by BohdanT » Logged
cfbsoftware
Full Member
***
Posts: 107


WWW
« Reply #9 on: November 07, 2009, 03:31:29 AM »

it was a joke.
OK - LOL Wink

Quote
Bad that branch A2 under the ARM-processor is now destroyed.

Is that related to FOR statements or are you now talking about something else?

Quote
And the example that you have, it is better to put them in constants.
I don't see how it is possible to conclude that without knowing the requirements of problem being solved e.g.

1. How many different values are involved? (39)
2. How often is the initialisation code executed per application execution? (once)
3. Should the initialisation code be memory efficient / speed efficient? (memory - see (2))
4. Is the (floating point) code compiled on the target processor or cross-compiled? (cross-compiled)

Perhaps a more obvious real-world example of a useful ARRAY-initialisation FOR loop is:

Code:
  FOR i := 1 TO LEN(primes) - 1 DO primes[i] := ODD(i) END;
  primes[2] := TRUE;
Logged

Chris Burrows
Astrobe v7.0 (Feb 2019): Oberon for ARM Cortex-M3, M4 and M7 Microcontrollers
http://www.astrobe.com
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!