Well this is a new one for me. I'm working from home on a work project that requires an adjustable "success" rate.
I'm setting a parameter which displays a pseudo percentage to the user that can be set from 10% - 90% giving the likely success. This is then used to create a large array of values which is filled with lesser or greater numbers of "success" values.
The intention is that I end up with an array that looks like:
1111111111111112345111111111111111 for 10%
or:
1123451123451123451123451123451123 for 90%
I pass my Sub routine a parameter which has the Likelihood value passed to it, along with the maximum value (5 in the above examples). The likelihood is adjusted from 1 - 9 (displayed as 10% - 90%) . As I want high percentages to increase the chance of success, I simply deduct the Likelihood value from 10.
To increase the steps of variation, I was trying to double the value of my likelihood variable.
Multiplying it by 2 causes a compiler error that the variable was not declared.
Multiplying by values other than 2 do not cause any error. As when I tried multiplying by 3 the variation seemed about right anyway, it isn't a problem but I'm confused as to why I can't multiply by 2.
SubShowAnimatedScroll(InMaximumValueAsByte,InLikelihoodAsByte)DimWin_ValueAsByteDimCurrValueAsByteDimJumpCountAsByteDimArrayLocAsByteDimFillValueAsByteDimWinArray(150)DimLocationAsByteLetArrayLoc=1LetFillValue=StdValueForArrayLoc=1to150Step1LetWinArray(ArrayLoc)=FillValueNextLetJumpCount=1LetFillValue=1LetLikeliHood=10-LikeliHood'Higher numbers give lower chances of winningLetLikeliHood=LikeliHood*3'this compiles' Let LikeliHood = LikeliHood * 2 'this does not compile? IfGameType=RandomGameThenForArrayLoc=1To150Step1LetJumpCount=JumpCount+1IfJumpCount>LikeliHoodThenLetWinArray(ArrayLoc)=FillValueLetFillValue=FillValue+1IfFillValue>MaximumValueThenLetJumpCount=1LetFillValue=1EndIfEndIfNextElse'This should never happen.,..LetWin=FixedValueWinExitSubEndIfEndSub
Last edit: Anobium 2021-10-10
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
;LetLikeliHood=10-LikeliHood'Higher numbers give lower chances of winningbankselLIKELIHOODmovfLIKELIHOOD,Wsublw10movwfLIKELIHOOD;LetLikeliHood=LikeliHood+Temp'Add a touch of skew to make it slightlybankselTEMPmovfTEMP,WbankselLIKELIHOODaddwfLIKELIHOOD,F;lesslikelytowinhighernumbers;Withoutthis,highermaximumvaluesarewonmoreoften.;;LetLikelihood=LikeliHood*2bcfSTATUS,CrlfLIKELIHOOD,F
Although I don't understand Assembler, it looks as though a left rotation is being attempted?
LetLikeliHood=10-LikeliHood'Higher numbers give lower chances of winningLetLikeliHood=LikeliHood+Temp'Add a touch of skew to make it slightly'less likely to win higher numbers'Without this, higher maximum values are won more often.'LetLikelihood=LikeliHood*2
This is the same section of Assembler code for the multiply by three:
;LetLikeliHood=10-LikeliHood'Higher numbers give lower chances of winningbankselLIKELIHOODmovfLIKELIHOOD,Wsublw10movwfLIKELIHOOD;LetLikeliHood=LikeliHood+Temp'Add a touch of skew to make it slightlybankselTEMPmovfTEMP,WbankselLIKELIHOODaddwfLIKELIHOOD,F;lesslikelytowinhighernumbers;Withoutthis,highermaximumvaluesarewonmoreoften.;;LetLikelihood=LikeliHood*3movfLIKELIHOOD,WmovwfSysBYTETempAmovlw3movwfSysBYTETempBpageselSysMultSubcallSysMultSubpagesel$movfSysBYTETempX,WmovwfLIKELIHOOD
That does look as though it is calling a multiplication routine?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anobium kindly looked at this for me. It would appear that a bug exists where if a byte parmeter to a subroutine is attempted to be multiplied by two (no other value) the compiler erroneously flags the variable as not declared.
The suggested work around is to cast the parameter as a word before performing the multiplication:
I managed without the multiplication at all in the end.
I tried adding it to itself at one point. For whatever reason, I don't think it worked as I expected. It could be that at that point I hadn't declared "LikeliHood" as In which has often caused issues with SubRoutine parameters in the past.
Of course as a work around, adding the variable to itself should indeed have the same effect as multiplying by two.
The initial error does still exist for the time being.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
;dim var as Byte;var=20movlw20movwfVAR,ACCESS;var=(var+var+var)-varaddwfVAR,W,ACCESSmovwfSysTemp1,ACCESSmovfVAR,W,ACCESSaddwfSysTemp1,W,ACCESSmovwfSysTemp2,ACCESSmovfVAR,W,ACCESSsubwfSysTemp2,W,ACCESSmovwfVAR,ACCESS;End
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
@stanleyella: Why dim vars in a sub, why not at the start of your code?
I spent a lot of time programming in Delphi where procedures and functions were mandatory. A similar procedure in Object Pascal would look like:
//Pseudo Pascal - It has been well over ten years since I wrote in Pascal, and I am sure this is not remotely Delphi compatible// Declare the procedure and required parametersTypeTMyProgamName=Class(TProgram)ProcedureSubCall(MaximumValue,Likelihood:Integer);end;//Type declaration endsvar;MyGlobalVar:Integer;implementationBeginProcedureTMyProgramName.SubCall(MaximumValue,Likelihood:Integer);Varn1,n2,n3:Integer;Beginn1:=MaximumValue;n2:=LikeliHood;n3:=LikeliHood*2;LikeliHood:=n2+((LikeliHood*2)+MaximumValue));IfMaximumValue=4ThenBeginn3:=likeliHood;MyGlobalVar:=MyGlobalVar+1;End;//If endsEnd;//Procedure endsEnd;//Program ends
In this case the variables n1, n2 and n3 would only be visible within the SubCall procedure. Any subsequent procedures would have to re-declare them before they could be used, the advantage is that you could do anything to those values and it wouldn't affect values in other procedures. The parameters passed would be mandatory in any calls to the procedure, and crucially, as the procedure was declared in the "Type" declaration, any calls to the procedure must have the parameter values as integer values, or integer variables. Attempting to call it with a LongInt value or LongInt variable (or other type of variable that wasn't explicitly of the Type Integer) would result in a compilation error with a 'Type Mismatch error'. This could catch errors where Byte and Word values/variables were mixed and could potentially overflow. MyGlobalVar would have it's value changed and that value (and that variable) would be visible to any subsequent procedures.
in GCB there is less advantage to declaring variables within subroutines using the 'Dim MyVariable As Byte' declaration as (so far as I understand) all variables declared using Dim are automatically Global in scope. But old habits die hard, and I do from time to time find myself declaring (pointlessly) them in this way.
Parameters passed to a subroutine in GCB are often passed only as an alias, where if a variable value is used in the call to the subroutine [ SubCall(AVariable, AnotherVariable) ] any changes to MaximumValue or LikeliHood directly affect the values of variables AVariable and AnotherVariable everywhere they might be used subsequently. This is why I have used an "In" declaration. The variables AVariable and AnotherVariable will now be unaffected by any maths within the SubCall subroutine.
If I could wave a magic wand, I'd love to see local variable scope in GCB. It would suit my methodolgy superbly. Due to the nature of the PIC device and the PIC assembler language, I'm not sure it is actually possible even with that magic wand.
Last edit: mkstevo 2020-03-29
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
In another commercial BASIC compiler, the variables declared inside a routine, even if they have the same name as other externals, are renamed with the suffix given by the name of the routine plus "_" plus the name of the variable.
In this way they remain confined within the routine.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
@JackJames :In another commercial BASIC compiler, the variables declared inside a routine, even if they have the same name as other externals, are renamed with the suffix given by the name of the routine plus "_" plus the name of the variable.
In this way they remain confined within the routine.
That does sound like one way of doing things.
Would that not be 'wasteful' of RAM though? I have not had problems with RAM on the devices I tend to use, but I can see that it might become problematic with some of the low end devices. An ideal case would be that the local variables were destroyed after leaving their local scope, though as I said earlier, I'm not sure that could be done on a PIC.
Last edit: mkstevo 2020-03-30
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Resolved
Well this is a new one for me. I'm working from home on a work project that requires an adjustable "success" rate.
I'm setting a parameter which displays a pseudo percentage to the user that can be set from 10% - 90% giving the likely success. This is then used to create a large array of values which is filled with lesser or greater numbers of "success" values.
The intention is that I end up with an array that looks like:
1111111111111112345111111111111111 for 10%
or:
1123451123451123451123451123451123 for 90%
I pass my Sub routine a parameter which has the Likelihood value passed to it, along with the maximum value (5 in the above examples). The likelihood is adjusted from 1 - 9 (displayed as 10% - 90%) . As I want high percentages to increase the chance of success, I simply deduct the Likelihood value from 10.
To increase the steps of variation, I was trying to double the value of my likelihood variable.
Multiplying it by 2 causes a compiler error that the variable was not declared.
Multiplying by values other than 2 do not cause any error. As when I tried multiplying by 3 the variation seemed about right anyway, it isn't a problem but I'm confused as to why I can't multiply by 2.
Last edit: Anobium 2021-10-10
Very hard to say without know the chip?
And, attaching the ASM of both cases would be good.
My guess. A total guess the method for x2 is shift register and x3 is calcualated.
The device is a PIC16F1829 (as ever for me!)
Here is the section that contains the error:
Although I don't understand Assembler, it looks as though a left rotation is being attempted?
Error returned:
Last edit: mkstevo 2020-03-27
Send me the source. i need to debug.
This is the same section of Assembler code for the multiply by three:
That does look as though it is calling a multiplication routine?
Sent by email, I hope that is alright? I couldn't see how to attach it to a PM.
Anobium kindly looked at this for me. It would appear that a bug exists where if a byte parmeter to a subroutine is attempted to be multiplied by two (no other value) the compiler erroneously flags the variable as not declared.
The suggested work around is to cast the parameter as a word before performing the multiplication:
Thanks Anobium.
Resolved in the latest compiler.
Evan
Resolved in the latest compiler.
Evan
Instead of multiply by 2
Try adding the value to itself... it is the same as multiplying by 2 but might be faster
LikeliHood = LikeliHood + LikeliHood
Last edit: stan cartwright 2020-03-27
I managed without the multiplication at all in the end.
I tried adding it to itself at one point. For whatever reason, I don't think it worked as I expected. It could be that at that point I hadn't declared "LikeliHood" as In which has often caused issues with SubRoutine parameters in the past.
Of course as a work around, adding the variable to itself should indeed have the same effect as multiplying by two.
The initial error does still exist for the time being.
If the compiler sees 'self' added to self 'self' then the compiler will optimize to 'shift left'.
.. which causes the same issue.
.
I did not realise that Anobium.
What does the compiler do with
var=(var+var+var)-var ? ....without me trying please.
as I don't do 328 asm
Last edit: stan cartwright 2020-03-27
Dunno. Do try.
I did and it doesn't use shift.
@Anobium: If the compiler sees 'self' added to self 'self' then the compiler will optimize to 'shift left'... Which causes the same issue.
Thanks for the explanation. I thought I'd tried it...
Last edit: mkstevo 2020-03-29
Yep. :-(
Where is Dim LikeliHood and as what ?
Why dim vars in a sub, why not at the start of your code?
Are you using #option explicit ?
Just thinking.
@stanleyella: Where is Dim LikeliHood?
Here:
@stanleyella: Why dim vars in a sub, why not at the start of your code?
I spent a lot of time programming in Delphi where procedures and functions were mandatory. A similar procedure in Object Pascal would look like:
In this case the variables n1, n2 and n3 would only be visible within the SubCall procedure. Any subsequent procedures would have to re-declare them before they could be used, the advantage is that you could do anything to those values and it wouldn't affect values in other procedures. The parameters passed would be mandatory in any calls to the procedure, and crucially, as the procedure was declared in the "Type" declaration, any calls to the procedure must have the parameter values as integer values, or integer variables. Attempting to call it with a LongInt value or LongInt variable (or other type of variable that wasn't explicitly of the Type Integer) would result in a compilation error with a 'Type Mismatch error'. This could catch errors where Byte and Word values/variables were mixed and could potentially overflow. MyGlobalVar would have it's value changed and that value (and that variable) would be visible to any subsequent procedures.
in GCB there is less advantage to declaring variables within subroutines using the 'Dim MyVariable As Byte' declaration as (so far as I understand) all variables declared using Dim are automatically Global in scope. But old habits die hard, and I do from time to time find myself declaring (pointlessly) them in this way.
Parameters passed to a subroutine in GCB are often passed only as an alias, where if a variable value is used in the call to the subroutine [ SubCall(AVariable, AnotherVariable) ] any changes to MaximumValue or LikeliHood directly affect the values of variables AVariable and AnotherVariable everywhere they might be used subsequently. This is why I have used an "In" declaration. The variables AVariable and AnotherVariable will now be unaffected by any maths within the SubCall subroutine.
If I could wave a magic wand, I'd love to see local variable scope in GCB. It would suit my methodolgy superbly. Due to the nature of the PIC device and the PIC assembler language, I'm not sure it is actually possible even with that magic wand.
Last edit: mkstevo 2020-03-29
Magic wand request has been on the list a while. :-)
@evanvennn :Magic wand request has been on the list a while. :-)
Ooh... Now I'm excited!
I only learnt interpreted simple basic in 1981. Gosub was simpler then.
In another commercial BASIC compiler, the variables declared inside a routine, even if they have the same name as other externals, are renamed with the suffix given by the name of the routine plus "_" plus the name of the variable.
In this way they remain confined within the routine.
Yes, Noted.
@JackJames :In another commercial BASIC compiler, the variables declared inside a routine, even if they have the same name as other externals, are renamed with the suffix given by the name of the routine plus "_" plus the name of the variable.
In this way they remain confined within the routine.
That does sound like one way of doing things.
Would that not be 'wasteful' of RAM though? I have not had problems with RAM on the devices I tend to use, but I can see that it might become problematic with some of the low end devices. An ideal case would be that the local variables were destroyed after leaving their local scope, though as I said earlier, I'm not sure that could be done on a PIC.
Last edit: mkstevo 2020-03-30