if substr(#array(*),2,1)

Hello all!

Sometimes Natural surprises me positively.

define data local
01 #array(A10/10) init <'AAA','AAB','ABC','ADF','AZZ','BBC'>
end-define
if substr(#array(*),2,1) = "B" /* <-- works!
write 'true'
else
write 'false'
end-if
end

I didn’t expect that a substring on the whole array works. But it does. :smiley:

Regards

Matthias

Hi Matthias;

I know you probably put as simple an example together to demonstrate a really great feature of Natural.

However, programmers tend to cut and paste code from this forum and SAG-L, hence words of warning should be posted as well. In this case, it should be pointed out that you probably should almost never use SUBSTRING when the last two arguments are constants. The reason is quite simple, REDEFINE is far faster than SUBSTRING.

I said almost never. If I am many pages deep in a Natural program, and I need such functionality, and, this is a one time use of the functionality, and I am too lazy to go back to the LDA to add the REDEFINE, I use SUBSTRING.

BUT, if this functionality is inside a loop processing a file with 10 million records, …
well the following example shows the performance cost:

DEFINE DATA LOCAL
1 #A (A5)
1 REDEFINE #A
2 FILLER 2X
2 #B (A2)
1 #LOOP (I4)
1 #CPU-START (I4)
1 #CPU-ELAPSED (I4)
END-DEFINE
*
INCLUDE AATITLER
INCLUDE AASETC
*
MOVE *CPU-TIME TO #CPU-START
SETA. SETTIME
FOR #LOOP = 1 TO 1000000
IF SUBSTRING (#A,3,2) = ‘QQ’
IGNORE
END-IF
END-FOR
COMPUTE #CPU-ELAPSED = *CPU-TIME - #CPU-START
WRITE 5T ‘SUBSTRING TIME’ #CPU-ELAPSED *TIMD (SETA.) //
*
MOVE *CPU-TIME TO #CPU-START
SETB. SETTIME
FOR #LOOP = 1 TO 1000000
IF #B = ‘QQ’
IGNORE
END-IF
END-FOR
COMPUTE #CPU-ELAPSED = *CPU-TIME - #CPU-START
WRITE 5T ‘REDEFINE TIME’ #CPU-ELAPSED *TIMD (SETB.) //
*
MOVE *CPU-TIME TO #CPU-START
SETC. SETTIME
FOR #LOOP = 1 TO 1000000
IGNORE
END-FOR
COMPUTE #CPU-ELAPSED = *CPU-TIME - #CPU-START
WRITE 5T ‘FOR TIME’ #CPU-ELAPSED *TIMD (SETC.)

END

PAGE #   1                    DATE:    10/16/10
PROGRAM: SUBS01               LIBRARY: INSIDE

SUBSTRING TIME          77        8


REDEFINE TIME          47        5


FOR TIME          26        2

After subtracting out the FOR loop times, the Elapsed times are 51 for SUBSTRING and 21 for REDEFINE; the CPU times are 3 versus 6. Either way, at least two to one.

If the definitions are changed a bit, say to:

1 #A (A500)
1 REDEFINE #A
2 FILLER 420X
2 #B (A2)

The REDEFINE times, as one would expect, do not change. The SUBSTRING times increase substantially.

steve

aka The CPU policeman

On Nat 6.1@Solaris the difference is not that big:

Next interesting thing is: If I do that array-substr-thing, the CPU-times are almost equal:

define data local
01 #array(A10/10) init <'AAA','AAB','ABC','ADF','AZZ','BBC'>
01 redefine #array
02 #array2(10)
03 #a1    (A1)
03 #a2    (A1)
03 #a3    (A1)
03 #a4    (A1)
03 #a5    (A1)
03 #a6    (A1)
03 #a7    (A1)
03 #a8    (A1)
03 #a9    (A1)
03 #a10   (A1)
1 #LOOP (I4)
1 #CPU-START (I4)
1 #CPU-ELAPSED (I4)
END-DEFINE
*
MOVE *CPU-TIME TO #CPU-START
SETA. SETTIME
FOR #LOOP = 1 TO 1000000
IF substr(#array(*),2,1) = 'B'
IGNORE
END-IF
END-FOR
COMPUTE #CPU-ELAPSED = *CPU-TIME - #CPU-START
WRITE 5T 'SUBSTRING TIME' #CPU-ELAPSED *TIMD (SETA.) //
*
MOVE *CPU-TIME TO #CPU-START
SETB. SETTIME
FOR #LOOP = 1 TO 1000000
IF #a2(*) = 'B'
IGNORE
END-IF
END-FOR
COMPUTE #CPU-ELAPSED = *CPU-TIME - #CPU-START
WRITE 5T 'REDEFINE TIME' #CPU-ELAPSED *TIMD (SETB.) //
*
MOVE *CPU-TIME TO #CPU-START
SETC. SETTIME
FOR #LOOP = 1 TO 1000000
IGNORE
END-FOR
COMPUTE #CPU-ELAPSED = *CPU-TIME - #CPU-START
WRITE 5T 'FOR TIME' #CPU-ELAPSED *TIMD (SETC.)
*
end

Result on Solaris:

Hi Matthias;

I wonder why there is so much difference between Solaris and my plain vanilla PC? Also, why your numbers are so much higher than mine for the same number of loop iterations. I have a 2.6 Gig PC with 4 gig of memory. There is a virus checker in the background. What else is typically running on your system?

I will try to test this on a mainframe this week. Curious what happens there.

steve

Hi Steve,

we’re using SPARC-Processors. I don’t know how old they are on our Test-System…

Some ADABAS-Databases, other SAG-products, some java-stuff … but the CPU is > 90% idle at the moment.

Matthias

I did get a chance to run the code on the mainframe. The two times are basically identical (substring vs redefine).

If you think about it, the two times should be identical. The compiler should “see” the fixed start for the substring, and the fixed number of characters, and basically act as if there is a redefine.

On the mainframe it apparently does this. On the PC, and on Solaris, this does not appear to be the case. It is almost as if there were variables rather than constants for the start and extent parameters. As soon as I get a chance, I will compare IF SUBSTRING (#A,3,2) = ‘QQ’ with IF SUBSTRING (#A,#START,#LENGTH) = ‘QQ’ where #START is 3 and #LENGTH is 2. My guess is that on the PC they will be closer to one another than the comparison with REDEFINE.

steve

I found a documentation saying:
4X CPU 1200MHz
64 GB Memory

So the slower times on Solaris are OK.

Sounds logical. But maybe there are some other factors - like the method of memory addressing etc.