Code: Select all
75 PRINT actual$
Thanks for clarifying.
Mike
Code: Select all
75 PRINT actual$
It's not at all clear in the published listings which code is hellomike's and which is yours, but for the avoidance of doubt i% (i.e. a 32-bit integer) is entirely suitable as an array index (as in b&(i%)) but not as a pointer (as in ?i%). A pointer should be either a 64-bit integer (e.g. i%%) or a variant (e.g. i).
Code: Select all
p%%=PTR(a$):e%%=p%%+LEN(a$)-1
FOR i%% = p%% TO e%%
IF ?i%>64 IF ?i%<91 n%+=1
NEXT
Code: Select all
FOR i%%=PTR(a$) TO PTR(a$)+LEN(a$)-1
IF ?i%>64 IF ?i%<91 n%+=1
NEXT
Code: Select all
Profiler report for count_capitals_speed.bbc
Fri. 03 Mar 2023, 10:44:20
Figures in the first column indicate approximate
time in milliseconds spent in each program line.
Figures in the second column indicate approximate
percentage of the time spent in each program line.
Time spent profiling: 83.098 seconds.
0: HIMEM = PAGE + 10000000
0:
2: test$ = STRING$(10000, "This is a TEST string. It has some Capital Letters, some 123456789 numbers, and some that are NOT so capital.")
4: TIME = 0 : PRINT FNstr_capsJH(test$), TIME
0: QUIT
0:
0: DEFFNstr_capsJH(a$)
0: LOCAL I%,N%
0: IF a$="":=0
0: FOR I%=1 TO LEN a$
48608: 58.49 IF MID$(a$,I%,1)>="@" THEN
34314: 41.29 IF MID$(a$,I%,1)<="_"THEN
20: 0.02 N%+=1
18: 0.02 ENDIF
22: 0.03 ENDIF
110: 0.13 NEXT
0: =N%
0:
0: Libraries and immediate mode
I've been puzzling over this for a while, and I still don't get it. Why would any value of either of the numeric parameters cause the string that's being sliced to get altered?Hated Moron wrote: ↑Tue 28 Feb 2023, 17:29
But of course you're right that the reason Jonathan's code is so terribly slow is not primarily the loop, it's the use of the MID$() string-slicing function. And the reason that MID$() is so slow is because it has to assume that evaluating the numeric parameter(s) might modify the string (although it probably won't) and therefore it has to copy the string first.
Why does the syntax matter? Is it something to do with how parameters to (any) function get passed to it? And in particular, the first parameter?Hated Moron wrote: ↑Tue 28 Feb 2023, 17:29 If the syntax of the MID$() function had been MID$(start, count, string$) rather than MID$(string$, start, count) it could be much faster,
It's unlikely, but since it's possible (and in that event the result of the MID$ function would be wrong) you can't risk it. There are several similar situations in the interpreter where you have to go to extra effort (sometimes with a performance cost) to ensure it still works correctly in 'edge cases'.JeremyNicoll wrote: ↑Fri 03 Mar 2023, 12:35 Why would any value of either of the numeric parameters cause the string that's being sliced to get altered?
Code: Select all
PROCtest(a$,b$)
....
DEF PROCtest(b$,a$)
...
ENDPROC
Because the parameter order matters. If the string was the final parameter to MID$, you could use its contents 'in situ' because there's no way they can have changed before the actual slicing operation is carried out. But when the string isn't the final parameter the evaluation of the subsequent parameter(s) could change the contents of the memory it occupies (occupied).Why does the syntax matter?
I would have expected the code inside however it is that you implement MID$ to validity check the values of 'start' and 'length' and either raise an error if they are (for 'start') outwith the length of the string, and (for 'length') longer than the remaining number of characters after the 'start' position, or if they're bad, simply return eg "" - which they do depends on your implementation choice for such things.Hated Moron wrote: ↑Fri 03 Mar 2023, 20:05It's unlikely, but since it's possible (and in that event the result of the MID$ function would be wrong) you can't risk it. There are several similar situations in the interpreter where you have to go to extra effort (sometimes with a performance cost) to ensure it still works correctly in 'edge cases'.JeremyNicoll wrote: ↑Fri 03 Mar 2023, 12:35 Why would any value of either of the numeric parameters cause the string that's being sliced to get altered?
When you say "If /you/ do it naively" ... do you mean "you" as in the implementer of the language?Hated Moron wrote: ↑Fri 03 Mar 2023, 20:05 There's a classic example of when passing parameters into a FN/PROC naively can fail:
If you do it naively a$ gets copied into b$ and then b$ gets copied into a$. Whoops!Code: Select all
PROCtest(a$,b$) .... DEF PROCtest(b$,a$) ... ENDPROC
Is that because the caller might code something likeHated Moron wrote: ↑Fri 03 Mar 2023, 20:05Because the parameter order matters. If the string was the final parameter to MID$, you could use its contents 'in situ' because there's no way they can have changed before the actual slicing operation is carried out. But when the string isn't the final parameter the evaluation of the subsequent parameter(s) could change the contents of the memory it occupies (occupied).
Code: Select all
A$="This is a test"
PRINT MID$(A$, FNfromlib)
PRINT A$
END
DEF FNfromlib
A$="The Quick Brown Fox"
=6
I'd have no expectations without first checking what the implementation was meant to do.hellomike wrote: ↑Sat 04 Mar 2023, 11:04 Consider this:What would you expect (want) the two PRINT statements to print?Code: Select all
A$="This is a test" PRINT MID$(A$, FNfromlib) PRINT A$ END DEF FNfromlib A$="The Quick Brown Fox" =6
Code: Select all
GLOBAL_A$="This is a test"
PRINT MID$(GLOBAL_A$, FNupdate_globals_and_set_pos)
PRINT GLOBAL_A$
END
Code: Select all
GLOBAL_A$="This is a test"
frompos = FNupdate_globals_and_set_pos ; REM remember this may reset GLOBAL_A$
PRINT MID$(GLOBAL_A$, frompos)
PRINT GLOBAL_A$
END