Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : MMBasic - Odd behaviour OR I've lost the plot
Author | Message | ||||
Nimue Guru Joined: 06/08/2020 Location: United KingdomPosts: 367 |
Away from the CMM2 today and coding a class via MMBasic (DOS). Created a function to convert a decimal to a binary (8 bit) number. The function works fine when called individually -- binary(10) for example. But when I wrap the function in a For/Next loop -- say I want to print all the binary from a to b -- it fails, with some odd behaviour. Happy to acknowledge the issue is probably my code -- but after dropping this into class and testing it --- no idea why. Any insight greatly recieved: Function binary(x) As string 'astr$ assembles the binary representation, in reverse Local astr$= Str$(x Mod 2) ' intial value Local rev$="" 'define the reversed string Local pad = 0 'the padding to make up to 8 bits Do If x Mod 2 = 1 Then ' ie if there is a remainder x = x \ 2 'divide and round down Else x = x / 2 ' actual division End If astr$ = astr$ + Str$(x Mod 2) ' assemble a string of the bits Loop While x <> 0 pad=8-Len(astr$) ' pad it out to 8 bits For n = 1 To pad astr$=astr$+"0" Next n For i = 8 To 1 Step -1 rev$=rev$+Mid$(astr$,i,1) ' reverse the string so it reads left to right Next i binary$=(rev$) 'dump rev$ into binary$ so that the function returns it End Function ''Test the function Print "Binary of 10 = " binary(10) 'test the function - should produce 00001010 (ie 2^3 + 2^1 = 8 + 2 = 10) Print "Binary of 128 = " binary(128) 'test - should produce 10000000 x = 11 Print "Binary of " x " = " binary(x) ' passing x as a variable produces the right answer ''' works as expected until here........... '' but when I wrap the function in a loop, all hell breaks lose..... '' uncomment for fun Print "" For x = 8 To 16 'arbitary range to convert from decimal to binary 'Print "Binary of " x " = " binary(x) '' if you uncomment this and observe ???? Print x '' if you leave the above line commented, but uncomment this >> loop clearly working Next x Entropy is not what it used to be |
||||
thwill Guru Joined: 16/09/2019 Location: United KingdomPosts: 3838 |
I had the briefest of looks, but: Variables are passed by reference, so in your code a call to binary(x) actually changes the value of x in the caller. Tom Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 8573 |
Variables are passed by reference in MMBasic. Take a local copy in the function and only change the copy |
||||
Nimue Guru Joined: 06/08/2020 Location: United KingdomPosts: 367 |
OK - get that. So how do I programmatically call the function inside a loop ? Sorry if I'm being dense. Nim Entropy is not what it used to be |
||||
Nimue Guru Joined: 06/08/2020 Location: United KingdomPosts: 367 |
Got it -- I think. Off for a play.. (ie serious tweaking) Many thanks Nim Entropy is not what it used to be |
||||
Nimue Guru Joined: 06/08/2020 Location: United KingdomPosts: 367 |
Solved.... Changing references to x in the function to "num" and defining "num" as "Local num = x" solved it. Thank you!!! Nim Entropy is not what it used to be |
||||
CaptainBoing Guru Joined: 07/09/2016 Location: United KingdomPosts: 1985 |
Evening Nim probably missing something - is the idea of the above code to teach *how* to do this or to end up with a binary representation of you number Don't want to go down the Bin$(x,8) route without giving you due credit. h |
||||
Nimue Guru Joined: 06/08/2020 Location: United KingdomPosts: 367 |
Good question. I am teaching a group of students using the CMM2. We are making a reusable library of "functions" - so to answer your Q - its about teaching how to do this, not actually converting from decimal to binary. My example was more about the behaviour of the code, which turned out to be about passing by reference not value (which I sorted now). As an extension, they are trying to figure out how to convert from any base (including negative bases) into any other base. As in baseconv(15,2,3) --> in this case -- convert 15 in base 2 to 15 in base 3 --> needless to say they are no where near this level of sophistication yet. Some interesting math when you use negative bases. Cheers Nim Entropy is not what it used to be |
||||
Nimue Guru Joined: 06/08/2020 Location: United KingdomPosts: 367 |
|
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5895 |
Just to add more confusion to the mix. Normally MMBasic complains if you define a variable with the same name but different type. You can do this within a sub or function because it is local. But when it comes to passing byref, things can get interesting. OPTION EXPLICIT DIM INTEGER s = 1245 DIM INTEGER k = 1245 PRINT "Same 'name' but different types" PRINT mytest(s) PRINT s PRINT "Same 'name' and same types = byref" s = 1245 PRINT mytest2(s) PRINT s PRINT "Different 'name' and same types = byref" k = 1245 PRINT mytest2(k) PRINT k FUNCTION mytest(s AS FLOAT) s = s/2 mytest = s END FUNCTION FUNCTION mytest2(s AS INTEGER) s = s/2 mytest2 = s END FUNCTION It will catch you out if you are not using OPTION DEFAULT NONE and end up with floats by default then declare an INTEGER. Jim VK7JH MMedit  MMBasic Help |
||||
capsikin Guru Joined: 30/06/2020 Location: AustraliaPosts: 341 |
I didn't know you could refer to a string function called binary as binary$ (when you set its return value). When I've done that sort of thing with variables it gave an error, and it seems clearer to either always use or always omit the $. |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3650 |
A thought in passing: If x Mod 2 = 1 Then ' ie if there is a remainder x = x \ 2 'divide and round down Else x = x / 2 ' actual division End If Can probably just be x = x \ 2 John |
||||
Nimue Guru Joined: 06/08/2020 Location: United KingdomPosts: 367 |
If x Mod 2 = 1 Then ' ie if there is a remainder x = x \ 2 'divide and round down Else x = x / 2 ' actual division End If Can probably just be x = x \ 2 John Nice stop -- to be fair, I was more focused on be overly explicit with the kiddos, but also in fairness, missed that one. Cheers Nim Entropy is not what it used to be |
||||
JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 3650 |
Might be interesting to see if any of the kids spot it... John |
||||
Womble Senior Member Joined: 09/07/2020 Location: United KingdomPosts: 267 |
John Thats evil John I didn't until I thought about it and checked the operator list in the manual |
||||
Nimue Guru Joined: 06/08/2020 Location: United KingdomPosts: 367 |
John Thats evil John I didn't until I thought about it and checked the operator list in the manual / vs \ is really quite an interesting teaching point. Many learners use them interchangeably when "doing math" -- ie 13 / 3 = compared with 13 \ 3 = many teachers don't pick up the difference as many don't realise there is symbolically quite a difference. One lovely thing of the CMM2 it that it give me an excuse to teach this stuff.... Nim Entropy is not what it used to be |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5895 |
/ vs \ is really quite an interesting teaching point. Many learners use them interchangeably when "doing math" -- ie 13 / 3 = compared with 13 \ 3 = many teachers don't pick up the difference as many don't realise there is symbolically quite a difference. One lovely thing of the CMM2 it that it give me an excuse to teach this stuff.... Nim Try adding INT FIX and CINT into the mix. Integer division is not the same as INT for negative numbers \ rounds towards zero, not down. DIM FLOAT x FOR x = -5 TO 5 div x NEXT x END SUB div(x) PRINT "x ";x PRINT "x/2 ";x/2 PRINT "x\2 ";x\2 PRINT "fix(x/2) ";FIX(x/2) PRINT "int(x/2) ";INT(x/2) PRINT "cint(x/2) ";CINT(x/2) END SUB Jim VK7JH MMedit  MMBasic Help |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5895 |
This is a better example of the differences (and pitfalls) DIM FLOAT n,k DIM INTEGER m PRINT "N INT(N) CINT(N) FIX(N) n\1 k\2 m" FOR n = -3 TO 3 STEP 0.25 m = n ' assign a float to an integer k = n * 2 PRINT STR$(n,2,2),,INT(n),,CINT(n),,FIX(n),,n\1,,k\2,,m NEXT n N INT(N) CINT(N) FIX(N) n\1 k\2 m -3.00 -3 -3 -3 -3 -3 -3 -2.75 -3 -3 -2 -3 -3 -3 -2.50 -3 -3 -2 -3 -2 -3 -2.25 -3 -2 -2 -2 -2 -2 -2.00 -2 -2 -2 -2 -2 -2 -1.75 -2 -2 -1 -2 -2 -2 -1.50 -2 -2 -1 -2 -1 -2 -1.25 -2 -1 -1 -1 -1 -1 -1.00 -1 -1 -1 -1 -1 -1 -0.75 -1 -1 0 -1 -1 -1 -0.50 -1 -1 0 -1 0 -1 -0.25 -1 0 0 0 0 0 0.00 0 0 0 0 0 0 0.25 0 0 0 0 0 0 0.50 0 1 0 1 0 1 0.75 0 1 0 1 1 1 1.00 1 1 1 1 1 1 1.25 1 1 1 1 1 1 1.50 1 2 1 2 1 2 1.75 1 2 1 2 2 2 2.00 2 2 2 2 2 2 2.25 2 2 2 2 2 2 2.50 2 3 2 3 2 3 2.75 2 3 2 3 3 3 3.00 3 3 3 3 3 3 It aligns better on screen. Between the floating point rounding and different methods, life gets 'interesting' Jim VK7JH MMedit  MMBasic Help |
||||
Print this page |