![]() |
Forum Index : Microcontroller and PC projects : When not to convert C to BASIC
Author | Message | ||||
BobDevries![]() Senior Member ![]() Joined: 08/06/2011 Location: AustraliaPosts: 266 |
Hello all, well, after a day of bashing my skull against a brick wall, I finally see the light. I've been trying to re-create the C macros isdigit(), isalnum() et al. without success. I found out this morning, that these macros actually use a lookup table and use the value of the character as an index into the table, there to grab the attributes needed for the macro that was called. So now I've gone back to the non-recommended (in C) way like this: Function isdigit(IN$) X$=Left$(IN$,1): X=Asc(X$) If X > &H2f And X < &H3a Then isdigit = 1 Else isdigit = 0 End Function Why is it not recommended? 'Cos it doesn't work on all character sets! However, since the MM uses just one such, it's really immaterial. I'm writing a library of such functions for future use. REM Just some trivial programming information for you all. Regards, Bob Devries Dalby, QLD, Australia |
||||
BobD![]() Guru ![]() Joined: 07/12/2011 Location: AustraliaPosts: 935 |
Bob How far do you intend to go with checking character attributes? Check a character is UC, LC, NUM, CTRL, Alt, Function etc.? Some characters would have more than one of these attributes. A table would be 256 bytes and could be defined in the MMBasic firmware for lookup. A character could have up to 8 different attributes based on 8 bits at the index position. Lookup would be the table address (an MMBasic variable) + the character value. It may be easier to build functions that way? Any thoughts? Anyone? Bob |
||||
kiiid Guru ![]() Joined: 11/05/2013 Location: United KingdomPosts: 671 |
I see nothing wrong in the conversion. If it works with ASCII, that is in most cases enough in the non-PC world. I would only have simplified it a bit: function isdigit(left$(in$,1)) isdigit=val(in$) end function http://rittle.org -------------- |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6220 |
using val(IN$) would not find zero I prefer INSTR. It is useful for punctuation, digits, white space etc as well. Function isdigit(IN$) X$=Left$(IN$,1) If instr("0123456789",x$)> 0 Then isdigit = 1 Else isdigit = 0 End Function Jim VK7JH MMedit |
||||
kiiid Guru ![]() Joined: 11/05/2013 Location: United KingdomPosts: 671 |
Would it? I haven't used it for so long that I have forgotten... ![]() INSTR is also a good choice anyway http://rittle.org -------------- |
||||
BobDevries![]() Senior Member ![]() Joined: 08/06/2011 Location: AustraliaPosts: 266 |
Just by way of testing that, I found an anomoly: ? VAL("A") returns 0 as expected, but ? VAL("0") returns 00 Why? I condensed the code of isdigit to: function isdigit(IN$) IF INSTR(1,"0123456789",LEFT$(IN$,1)) > 0 then isdigit = 1 else isdigit = 0 end function Regards, Bob Devries Dalby, QLD, Australia |
||||
shoebuckle Senior Member ![]() Joined: 21/01/2012 Location: AustraliaPosts: 189 |
I like the simplicity of your IsDigit() function but I was curious to see how fast it was compared with a simple range test and whether it was quicker as a Function or a Subroutine. I tried an alpha test instead of numeric and because some letters are used more frequently than others in your native language, I tested with a straight alphabet and with a sequence-modified alphabet. Using a text document I happened to have, I first ran it through ALHHANUM to find the frequency of each alphabetic character to set up the modified alphabet sequence (it contains 87,840 characters). The results of running the 6 small programs show that there is a little under 7% difference in speed between the slowest (Pgm 1) and fastest (Pgm 4), not really enough to worry about which technique is used. The times were obtained on a Mono Maximite. Cheers, Hugh Using SUB Using Function Instr, A-Z Alphabet Seq Pgm 1 66606 Pgm 3 64669 Instr, Mod Alphabet Seq Pgm 2 64089 Pgm 4 62153 IF/THEN Range test Pgm 5 66474 Phm 6 65188 Program 1 Open "taking.txt" For input As 1
Alpha$="abcdefghijklmnopqrstuvwxyz" Timer=0 Do a$=LCase$(Input$(1, #1)) alphatest(a$,p) Print p; Loop Until Eof(1) Print Timer End Sub Alphatest(b$,ptr) ptr=Instr(1,alpha$,b$) End Sub Program 2 Open "taking.txt" For input As 1
Alpha$="eatinosrcdhlmfgpuwbkvyjqxz" Timer=0 Do a$=LCase$(Input$(1, #1)) alphatest(a$,p) Print p; Loop Until Eof(1) Print Timer End Sub Alphatest(b$,ptr) ptr=Instr(1,alpha$,b$) End Sub Program 3 Open "taking.txt" For input As 1
Alpha$="abcdefghijklmnopqrstuvwxyz" Timer=0 Do a$=LCase$(Input$(1, #1)) Print IsAlpha(a$); Loop Until Eof(1) Print Timer End Function IsAlpha(b$) IsAlpha=Instr(1,alpha$,b$) End Function Program 4 Open "taking.txt" For input As 1
Alpha$="eatinosrcdhlmfgpuwbkvyjqxz" Timer=0 Do a$=LCase$(Input$(1, #1)) Print IsAlpha(a$); Loop Until Eof(1) Print Timer End Function IsAlpha(b$) IsAlpha=Instr(1,alpha$,b$) End Function Program 5 Open "taking.txt" For input As 1
Timer=0 Do a$=LCase$(Input$(1, #1)) alphatest(a$,p) Print p; Loop Until Eof(1) Print Timer End Sub Alphatest(b$,ptr) If b$>="a" And b$<="z" Then ptr=1 Else ptr=0 End Sub Program 6 Open "taking.txt" For input As 1
Timer=0 Do a$=LCase$(Input$(1, #1)) Print IsAlpha(a$); Loop Until Eof(1) Print Timer End Function IsAlpha(b$) If b$>="a" And b$<="z" Then isAlpha=1 Else IsAlpha=0 End Function |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 3998 |
Does this work? Function IsAlpha(b$) IsAlpha = (b$>="a" And b$<="z") End Function Maybe the parens aren't needed. Has to be faster. BTW, I think PRINT will be the major slow thing and hides the difference in speed. John |
||||
shoebuckle Senior Member ![]() Joined: 21/01/2012 Location: AustraliaPosts: 189 |
Yes John, it works and is faster. Replacing the line in Pgm 6's Function gives a time of 57468. Now if we: - Remove Print P; in programs 1,2 and 5 and - Replace Print IsAlpha(a$); with a=Isalpha(A$) in pgms 3,4, and 7 and run again we get: Pgm 1 30341 Pgm 2 30261 Pgm 3 29828 Pgm 4 29748 Pgm 5 35830 Pgm 6 35901 Pgm 7 28901 Using your IsAlpha=(b$>="a" and b$<="z") in Pgm 6 The objective was to test the speed of the code in the Sub or Function and see if it made much difference so, where possible I used the same overhead (calling code). You might complain that in removing the PRINT, I replaced the calling code in 3, 4 and 7 with an assignment statement a=IsAlpha(a$) however I believe this is valid as the SUB returns the value of the test in p which means both methods return a value to a variable. The argument against this is that you might use the Function back in the mainline to say, for instance: If IsAlpha(a$) then ... and this would be faster than using a SUB. Anyway you can see that there is little difference between using the straight alphabet and the modified alpha sequence (comparing the pairs 1 & 2 and 3 & 4). Likewise not much difference between 5 & 6 (Sub vs Function). All rather academic really, unless you are trying to squeeze the last ounce of performance out of the system. Cheers, Hugh |
||||
MicroBlocks![]() Guru ![]() Joined: 12/05/2012 Location: ThailandPosts: 2209 |
how about this one: The conversion to lowercase should be in the IsAlpa function to prevent wrong use. [code] Open "taking.txt" For input As 1 Timer=0 Do a=IsAlpha(Input$(1, #1)) Loop Until Eof(1) Print Timer End Function IsAlpha(b$) c = asc(b$) isAlpha=((c>64 and c<91) or ( c > 96 and c < 123)) End Function [/code] I am not sure if MMBasic shortcircuits, if not then this can be an alternative. [code] Function IsAlpha(b$) c = asc(b$) if c < 91) then IsAlpha = (c > 64) else if c < 123 then IsAlpha = (c > 96) end if end if End Function [/code] Microblocks. Build with logic. |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 3998 |
As it's not very sensitive to changes it suggests MMBasic is just very busy going round and round (tokenising and executing etc). Although how to speed it up is reasonably well known (compile / semi-compile, run from RAM, faster CPU, etc), does it matter? I mean - are people finding it is too slow? (Benchmarks are fun, of course.) John |
||||
MicroBlocks![]() Guru ![]() Joined: 12/05/2012 Location: ThailandPosts: 2209 |
If it can be made faster it is by definition too slow. :) It is a bit of a lost art unfortunately. Java is to blame for that. :) Microblocks. Build with logic. |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3270 |
I just tested that and it works fine (ie, returns 0 in both cases). Geoff Geoff Graham - http://geoffg.net |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 3998 |
LOL Except some actually may think it's true. Unless it's unacceptably slow, aim for maintainability, robustness etc. John |
||||
shoebuckle Senior Member ![]() Joined: 21/01/2012 Location: AustraliaPosts: 189 |
The first one takes 33920 The second 35002 (after making Endif all one word in both instances). You pays your money, you takes your choice! They all work. Hugh |
||||
MicroBlocks![]() Guru ![]() Joined: 12/05/2012 Location: ThailandPosts: 2209 |
Thanks for the test. It shows that string comparison is faster then numeric comparisons. An unexpected result. Probably have to do that numbers are floats instead of integers. Microblocks. Build with logic. |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |