CrazyBoss Posted March 25, 2017 Share Posted March 25, 2017 Hi guys. I started this thread for helping programmers to how to optimize Intybasic code. Warning: Optimized code can look like a mess, but actually runs faster E.G: (3 examples of code that do the same....) rem test1 if a=0 then #sy=$0180:#sa=$194A+bif a=1 then #sy=$0980:#sa=$194A+bif a=2 then #sy=$0180:#sa=$195A+bif a=3 then #sy=$0580:#sa=$196A+bif a=4 then #sy=$0980:#sa=$197A+bif a=5 then #sy=$0180:#sa=$197A+bif a=6 then #sy=$0D80:#sa=$198A+bif a=7 then #sy=$0580:#sa=$198A+b a=a+1:if a=8 then a=0 rem test 2 - same as test1 just skip other ifs when "a" is found. if a=0 then #sy=$0180:#sa=$194A+b:goto stopifaif a=1 then #sy=$0980:#sa=$194A+b:goto stopifaif a=2 then #sy=$0180:#sa=$195A+b:goto stopifaif a=3 then #sy=$0580:#sa=$196A+b:goto stopifaif a=4 then #sy=$0980:#sa=$197A+b:goto stopifaif a=5 then #sy=$0180:#sa=$197A+b:goto stopifaif a=6 then #sy=$0D80:#sa=$198A+b:goto stopifaif a=7 then #sy=$0580:#sa=$198A+b stopifa: a=a+1:if a=8 then a=0 rem test3 - use of "on a goto" on a goto a0,a1,a2,a3,a4,a5,a6,a7 a0: #sy=$0180:#sa=$194A+b:goto stopifaa1: #sy=$0980:#sa=$194A+b:goto stopifaa2: #sy=$0180:#sa=$195A+b:goto stopifaa3: #sy=$0580:#sa=$196A+b:goto stopifaa4: #sy=$0980:#sa=$197A+b:goto stopifa a5: #sy=$0180:#sa=$197A+b:goto stopifaa6: #sy=$0D80:#sa=$198A+b:goto stopifaa7: #sy=$0580:#sa=$198A+b stopifa: a=a+1:if a=8 then a=0 i tested the code using the frame as counter 1000 times loop mode 1 cls print at 1,<5>frame for #c=1 to 1000 rem insert code here next print at 21,<5>frame stop:goto stop test1 finished at frame 00299. test2 finished at frame 00227. test3 finished at frame 00169. I have also tested the "ON A GOTO" agains "IFs", it seems like, more ifs more avantage does "ON A GOTO" have against if. Ofcause assume its not picking the first choice all the time I think on two ifs the speed is almost the same. 2 Quote Link to comment Share on other sites More sharing options...
intvnut Posted March 25, 2017 Share Posted March 25, 2017 For this particular pattern, a lookup table would be the best of all, although ON-GOTO seems really close. I benchmarked all 4 options in one BAS file. As you can see from the screen shot, the ON-GOTO was just slightly slower than the table lookup. I measured this with IntyBASIC 1.2.8. table.bas mode 1 cls a = 0 wait #x = frame for #c=1 to 1000 if a=0 then #sy=$0180:#sa=$194A+b if a=1 then #sy=$0980:#sa=$194A+b if a=2 then #sy=$0180:#sa=$195A+b if a=3 then #sy=$0580:#sa=$196A+b if a=4 then #sy=$0980:#sa=$197A+b if a=5 then #sy=$0180:#sa=$197A+b if a=6 then #sy=$0D80:#sa=$198A+b if a=7 then #sy=$0580:#sa=$198A+b a=a+1:if a=8 then a=0 next #x = frame - #x print at 1,<5>#x a = 0 wait #x = frame for #c=1 to 1000 if a=0 then #sy=$0180:#sa=$194A+b:goto stopifa if a=1 then #sy=$0980:#sa=$194A+b:goto stopifa if a=2 then #sy=$0180:#sa=$195A+b:goto stopifa if a=3 then #sy=$0580:#sa=$196A+b:goto stopifa if a=4 then #sy=$0980:#sa=$197A+b:goto stopifa if a=5 then #sy=$0180:#sa=$197A+b:goto stopifa if a=6 then #sy=$0D80:#sa=$198A+b:goto stopifa if a=7 then #sy=$0580:#sa=$198A+b stopifa: a=a+1:if a=8 then a=0 next #x = frame - #x print at 21,<5>#x a = 0 wait #x = frame for #c=1 to 1000 on a goto a0,a1,a2,a3,a4,a5,a6,a7 a0: #sy=$0180:#sa=$194A+b:goto stopifa2 a1: #sy=$0980:#sa=$194A+b:goto stopifa2 a2: #sy=$0180:#sa=$195A+b:goto stopifa2 a3: #sy=$0580:#sa=$196A+b:goto stopifa2 a4: #sy=$0980:#sa=$197A+b:goto stopifa2 a5: #sy=$0180:#sa=$197A+b:goto stopifa2 a6: #sy=$0D80:#sa=$198A+b:goto stopifa2 a7: #sy=$0580:#sa=$198A+b stopifa2: a=a+1:if a=8 then a=0 next #x = frame - #x print at 41,<5>#x a = 0 wait #x = frame for #c=1 to 1000 #sy=ytbl(a) : #sa=atbl(a)+b a=a+1:if a=8 then a=0 next #x = frame - #x print at 61,<5>#x stop:goto stop ytbl: DATA $0180, $0980, $0180, $0580, $0980, $0180, $0D80, $0580 atbl: DATA $194A, $194A, $195A, $196A, $197A, $197A, $198A, $198A 2 Quote Link to comment Share on other sites More sharing options...
intvnut Posted March 25, 2017 Share Posted March 25, 2017 BTW, some benchmarking tips, when using FRAME as your measurement: Put a WAIT just before you grab FRAME the first time, so you're synced to the display interrupt Don't print the starting/ending frame number: It costs cycles to print! Instead, just copy the frame number to a variable and subtract at the end. Then print. The cost of the print won't be in the total. Lookup tables are your friends! Quote Link to comment Share on other sites More sharing options...
intvnut Posted March 25, 2017 Share Posted March 25, 2017 Also, if you change this: a = a + 1 : if a = 8 then a = 0 to this: a = (a + 1) AND 7 everything gets faster: 1 Quote Link to comment Share on other sites More sharing options...
CrazyBoss Posted March 25, 2017 Author Share Posted March 25, 2017 nice tips thanks for the input, I hope other people will share there tips, so we all can learn how to write opmized code Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted March 25, 2017 Share Posted March 25, 2017 The "On GoTo" is useful as a pattern because it covers conditional value retrieval as well as conditional code execution. If your values fit neatly in a look-up table, that is obviously the best choice. However, if they are computed or if you need to do work based on a particular condition, the "On GoTo" would be the best alternative. If your program has the need of both of these features (to wit, conditional value retrieval and code execution), and you are easily confused like some of us are, then sticking to a pattern that does both may help make your code easier to read and more predictable, at a slight cost in performance. As with many things, your mileage may vary. -dZ. 2 Quote Link to comment Share on other sites More sharing options...
fsuinnc Posted March 25, 2017 Share Posted March 25, 2017 Also, if you change this: a = a + 1 : if a = 8 then a = 0 to this: a = (a + 1) AND 7 everything gets faster: table2_bas.gif That is unreal. I don't really understand how AND works but I understand the result. I realize the difference is small overall but I'm very impressed. now I will need to look at all the loops in my code and see if I can save some cycles with lookup tables,On Goto and using the AND in my counting.. Quote Link to comment Share on other sites More sharing options...
+nanochess Posted March 25, 2017 Share Posted March 25, 2017 I've optimized more IntyBASIC and the remainder operator converts to AND operator for most power of 2 constants. a = a % 8 same as a = a AND 7 a = a % 16 same as a = a AND 15 This is the same because given the inherent slowness of CP1610 processor, I've keeped the unsigned nature of division and remainder, because the test for signedness would be very slow. Anyway if you ever need signed division, this would be the right way. IF a < 0 THEN a = -(-a / b) ELSE a = a / b 1 Quote Link to comment Share on other sites More sharing options...
Rev Posted March 25, 2017 Share Posted March 25, 2017 (edited) Here is a visual for any dummies that wander into this thread. **cough** cmart **cough** Edited March 25, 2017 by Rev Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted March 25, 2017 Share Posted March 25, 2017 (edited) That is unreal. I don't really understand how AND works but I understand the result. I realize the difference is small overall but I'm very impressed. now I will need to look at all the loops in my code and see if I can save some cycles with lookup tables,On Goto and using the AND in my counting.. Bitwise AND is simple to understand, it even follows some intuitive common sense. When you apply AND on two expressions, the result is only true when both are true. In bits, this means that the result is "1" only when both inputs are "1". For instance: A AND B = C ----------- 0 0 0 0 1 0 1 0 0 1 1 1 You can extend this by applying the same function on non-binary numbers. In such cases, each individual bit on one number is ANDed with its corresponding bit on the other. Like this: 5 = 00000101 3 = 00000011 5 AND 3 = 00000101 AND 00000011 00000101 00000011 -------- 00000001 This is typically called "applying a mask" because it works in the same way as having a picture "masked out" with a cover that lets only certain parts shine through. In other words, you take any number and apply to it a "mask," and what comes out are only those bits that are "1" which are also represented in the mask. Now take the example of a mask like "7" (00000111). This is a very common mask because it means "mask out the number and only allow through those bits which fall on values less than 8." In other words, the number would be cycled from 0 through 7 and as soon as it gets higher than that, it will go back and cycle again by virtue of discarding the higher bits. Here's a demonstration: 0 : 00000000 AND 00000111 = -----000 = 0 1 : 00000001 AND 00000111 = -----001 = 1 2 : 00000010 AND 00000111 = -----010 = 2 3 : 00000011 AND 00000111 = -----011 = 3 4 : 00000100 AND 00000111 = -----100 = 4 5 : 00000101 AND 00000111 = -----101 = 5 6 : 00000110 AND 00000111 = -----110 = 6 7 : 00000111 AND 00000111 = -----111 = 7 8 : 00001000 AND 00000111 = -----000 = 0 9 : 00001001 AND 00000111 = -----001 = 1 10 : 00001010 AND 00000111 = -----010 = 2 11 : 00001011 AND 00000111 = -----011 = 3 12 : 00001100 AND 00000111 = -----100 = 4 13 : 00001101 AND 00000111 = -----101 = 5 14 : 00001110 AND 00000111 = -----110 = 6 15 : 00001111 AND 00000111 = -----111 = 7 ... Notice that this sort of "number cycling" is only possible because the mask is one less than a power of two (1 - 2^n). In other words, the mask fills up all the bits up to but not including the next power of two. Not only is this useful to cycle numbers within a power-of-two range, it also gives you the modulo of a number, that is, the reminder after division of a power-of-two. Remember, a division by a power-of-two is the same as shifting right, which causes it to discard the lower-bits. For instance: 5 ÷ 2 = 00000101 >> 1 = 00000010 ... (1) [ result ] [one bit shifted and discarded] This is the same as saying: 5 ÷ 2 = 2 ... reminder = 1 What the AND operator does in this case is that it masks only those bits which would have been shifted out and discarded, and leaves them in to the exclusion of the rest. The result is the reminder. 5 AND (2^1 - 1) = 00000101 AND 00000001 = -------1 I hope this helps. Other non-powers-of-two masks are very useful to test specific bits on registers, or to negate numbers, etc. -dZ. Edited March 25, 2017 by DZ-Jay 3 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.