How can I return true in COBOL - boolean

So I am making a program that checks if a number is divisible by another number or not. If it is its supposed to return true, otherwise false. Here's what I have so far.
P.S : I'm using IBM (GnuCOBOL v2.2 -std=ibm-strict -O2) to run this.
IDENTIFICATION DIVISION.
PROGRAM-ID. CHECKER.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 BASE PIC 9(5).
01 FACTOR PIC 9(2).
01 RESULT PIC 9(5).
88 TRU VALUE 0 .
88 FAL VALUE 1 THRU 99 .
PROCEDURE DIVISION.
CHECK-FOR-FACTOR SECTION.
IF FUNCTION MOD(BASE, FACTOR) = 0 THEN
SET TRU TO TRUE
ELSE
SET FAL TO TRUE
END-IF.
END PROGRAM CHECKER.
It gives me error saying invalid use of level 88. I'm sure I'm making a mistake, and I've searched for couple of days and I can't seem to find anything that can help me with it. Any ideas if it is possible in COBOL or does COBOL handle all the boolean stuff some other way ?
(Kindly do not reply with look up level 88 or some other stuff like that, I have already looked them up and they haven't been helping)

To return TRUE from a program you'd need an implementation that has boolean USAGE, define that in LINKAGE and specify it in PROCEDURE-DIVISION RETURNING true-item and also use CALL 'yourprog' RETURNING true-item.
Your specified environment GnuCOBOL doesn't have a boolean USAGE in 2021 and can't handle RETURNING phrase of PROCEDURE DIVISION in programs.
But you can use a very common extension to COBOL which is available in both IBM and GnuCOBOL:
Before the program ends MOVE RESULT TO RETURN-CODE (which is a global register) and in the calling program check its value (and reset it to zero).
Then it is only up to you what value means "true" (in your program it is 0).
As an alternative you could create a user-define function (FUNCTION-ID instead of PROGRAM-ID and use the RETURNING phrase to pass your result) - but that would mean you need to use IF FUNCTION instead of CALL + IF RETURN-CODE in each caller.

Related

Cimplicity Screen - one object/button that is dependent on hundreds of points

So I have created a huge screen that essentially just shows the robot status for every robot in this factory (individually)… At the very end of the project, they decided they want one object on the screen that blinks if any of the 300 robots fault. I am trying to think of a way to make this work. Maybe a global script of some kind? Problem is, I do not do much scripting in Cimplicity, so any help is appreciated.
All the points that are currently used on this screen (to indicate a fault) have very similar names… as in, the beginning is the same… so I was thinking of a script that could maybe recognize if a bit is high based on PART of it's string name characteristic. The end will change a little each time, but I am sure there is a way to only look for part of a string and negate the rest. If the end has to be hard coded, that's fine.
You can use a Python script in Cimplicity.
I will not go into detail on the use of python in Cimplicity, which is well described in the documentation indicated above.
Here's an example of what can be done... note that I don't have a way to test it and, of course, this will work if the name of your robots in the declaration follows the format Robot_1, Robot_2, Robot_3 ... Robot_10 ... Robot_300 and it also depends on the Name and the Type of the fault variable... as you didn't define it, I imagine it can be an integer, with ZERO indicating no error. But if you use something other than that, you can easily change it.
import cimplicity
(...)
OneRobotWithFault = False
# Here you get the values and check for fault
for i in range(0, 300):
pointName = f'MyFactory.Robot_{i}.FaultCode'
robotFaultCode = cimplicity.point_get(pointName)
if robotFaultCode > 0:
OneRobotWithFault = True
break
# Set the status to the variable "WeHaveRobotWithFault"
cimplicity.point_set("WeHaveRobotWithFault", OneRobotWithFault)

Anylogic - delay dependent on resources

I am trying to create a service that varies depending on the resources that are used.
For example if a nurse were to carry out the service it could take 10 - 35 mins, whereas if this is carried out by another member of staff it could take 5-25 minutes.
I have had a go - as in the picture below, however, what I've written doesn't seem to be working.
Resource dependent delays
Any help would be massively appreciated!
First, since the parameter "Delay time" accepts a value, you need to replace if-else statement with conditional expression "? :". The syntax is the following: condition ? value if true : value if false.
Moreover, your should use another condition to check if the agent has a resource unit from "Nurse":
agent.resourceUnitOfPool(Nurse) != null ? triangular(10, 15, 35) :
triangular(5, 10, 25)

set threshold as a function of autoThreshold

I have written a macro for ImageJ/FIJI to deconvolve my confocal microscopy images and run the "3D Object Counter" plugin. The macro successfully runs all required commands and saves all required data in the specified places.
However, I have found that the 3D-OC autothreshold (as shown in the plugin dialog box) is to stringent resulting in objects being lost or divided.
To remedy this I would like to reduce the autothreshold by a predetermined function something similar to what was done here (from:How to get threshold value used by auto threshold Plugin) which resulted in this code:
setAutoThreshold();
getThreshold(lower,upper);
v=setThreshold(lower,upper*0.5);
run("3D Objects Counter", "threshold="v" slice=10 min.=400 max.=20971520 objects statistics summary");
The idea was to call the AutoThreshold values, modify them and set them to a variable. However when these lines are run the following error is returned:
Number or numeric function expected in line 3.
v=<setThreshold>(lower,upper*0.5);
And if the variable is inserted directly into the threshold key for run(3D-OC) the following msg is encountered:
Numeric value expected in run() function
Key:"threshold"
Value or variable name:"setThreshold(lower,upper*0.5"
Any suggestions or help on how to designate the 3D-OC threshold value as a variable as described would be greatly appreciated (as would any work arounds of course :) ).
Cheers
Edit: After testing Jan's response below (which works perfectly), it appears I need to call the threshold set by the 3D-OC plugin. Anyone know how to do this?
The getThreshold(lower, upper) function returns the lower and upper threshold levels in the provided variables. There is no need to assign any value to a new variable, and as you observed, setThreshold does not have any return value.
Instead, you can use the value(s) returned from getThreshold and use them as parameters in the run method (in the correct way, by string concatenation, see here):
setAutoThreshold();
getThreshold(lower, v);
run("3D Objects Counter", "threshold=" + v + " slice=10 min.=400 max.=20971520 objects statistics summary");
Alternatively, you can use &v in the second parameter to avoid string concatenation in the last line (see the documentation for the run() macro function):
run("3D Objects Counter", "threshold=&v slice=10 min.=400 max.=20971520 objects statistics summary");
You might have to use the lower instead of the upper threshold value, depending on whether you count bright or dark objects.

How to reciprocate?

Actually I am coding a Matlab simulation where the AnchorID and SourceID will report to eachother. For example if I take an anchor 30 and source 50 it will collect all the agc values between these anchor and source and calculate rssi_dB and display them.Below mentioned is an example of anchor 30 and source id 50
Note: list of anchors ID's and source ID's are same. for e.g. 30 50 55 58 . These ID are both same for anchor and source.
function A30(BlinkSet)
for i=1:length(BlinkSet)
xAnchorID=30;
xSourceID=50;
a=BlinkSet{i}.AnchorID;
b=BlinkSet{i}.SourceID;
if xAnchorID==a && xSourceID==b
xagc=BlinkSet{i}.agc;
rssi_dB(i)=-(33+xagc*(89-33)/(29-1));
end
end
rssi_dB(rssi_dB==0)=[];
rssi_dBm=sum(rssi_dB(:))/length(rssi_dB);
disp([sprintf('The rssi value is %0.0f',rssi_dBm)]);
When I call the function in Matlab command window I get the rssi value of the above function.
Also my task is when I reciprocate the Anchor ID and source ID say Anchor as 50 and source as 30 like the function I have mentioned below I get an error which is mentioned after the function below.
function A50(BlinkSet)
for i=1:length(BlinkSet)
xAnchorID=50;
xSourceID=30;
a=BlinkSet{i}.AnchorID;
b=BlinkSet{i}.SourceID;
if xAnchorID==a && xSourceID==b
xagc=BlinkSet{i}.agc;
rssi_dB(i)=-(33+xagc*(89-33)/(29-1));
end
end
rssi_dB(rssi_dB==0)=[];
rssi_dBm=sum(rssi_dB(:))/length(rssi_dB);
disp([sprintf('The rssi value is %0.0f',rssi_dBm)]);
When I call this function I get an error as
??? Undefined function or variable "rssi_dB".
Error in ==> A50 at 14
rssi_dB(rssi_dB==0)=[];
Error in ==> main_reduced at 26
A50(BlinkSet);
In main function I have coded like this,
%A30(BlinkSet);
A50(BlinkSet);
Any help is highly appreciated.
In both of these functions, you only create the variable rssi_dB if execution enters the if statement within the loop (i.e., if xAnchorID==a && xSourceID==b is at some point true). Clearly, this code is never executed in your A50 function. Without knowing what is in BlinkSet it's a bit difficult to diagnose the exact problem, but this is the cause at least.
As a side note: it's not a good idea to create two separate functions to do this job when their code is almost identical. You should add an input argument to your function that allows it to do the job of both. In this particular case, all that changes is the value of xAnchorID and xSourceID, so you could just pass these in:
function srcToAnchorRssi(BlinkSet, xSourceID, xAnchorID)
% The rest of the function stays the same!
If you want to provide some defaults for these arguments, you can do, e.g.:
if nargin < 3 || isempty(xAnchorID), xAnchorID = 50; end
if nargin < 2 || isempty(xSourceID), xSourceID = 30; end
It's always a good idea to include an isempty in statements of this sort, so that your function supports syntax like myFunction(myArg1, [], myArg3). Also note that the order of the operands to || is crucial; if you did if isempty(theArgument) || nargin < theArgumentNumber and the user did not pass theArgument, then it would error in the isempty because theArgument would not exist as a local variable. We can get around this by swapping the operands' order because MATLAB is smart enough to know it doesn't have to evaluate the right operand if the left operand is true (note that this is also the case in many other programming languages).

COBOL add 0 to a Variable in COMPUTE

I ran into a strange statement when working on a COBOL program from $WORK.
We have a paragraph that is opening a cursor (from DB2), and the looping over it until it hits an EOT (in pseudo code):
... working storage ...
01 I PIC S9(9) COMP VALUE ZEROS.
01 WS-SUB PIC S9(4) COMP VALUE 0.
... code area ...
PARA-ONE.
PERFORM OPEN-CURSOR
PERFORM FETCH-CURSOR
PERFORM VARYING I FROM 1 BY 1 UNTIL SQLCODE = DB2EOT
do stuff here...
END-PERFORM
COMPUTE WS-SUB = I + 0
PERFORM CLOSE-CURSOR
... do another loop using WS-SUB ...
I'm wondering why that COMPUTE WS-SUB = I + 0 line is there. My understanding is that I will always at least be 1, because of the perform block above it (i.e., even if there is an EOT to start with, I will be set to one on that initial iteration).
Is that COMPUTE line even needed? Is it doing some implicit casting that I'm not aware of? Why would it be there? Why wouldn't you just MOVE I TO WS-SUB?
Call it stupid, but with some compilers (with the correct options in effect), given
01 SIGNED-NUMBER PIC S99 COMP-5 VALUE -1.
01 UNSIGNED-NUMBER PIC 99 COMP-5.
...
MOVE SIGNED-NUMBER TO UNSIGNED-NUMBER
DISPLAY UNSIGNED-NUMBER
results in: 255. But...
COMPUTE UNSIGNED-NUMBER = SIGNED-NUMBER + ZERO
results in: 1 (unsigned)
So to answer your question, this could be classified as a technique used cast signed numbers into unsigned numbers. However, in the code example you gave it makes no sense at all.
Note that the definition of "I" was (likely) coded by one programmer and of WS-SUB by another (naming is different, VALUE clause is different for same purpose).
Programmer 2 looks like "old school": PIC S9(4), signed and taking up all the digits which "fit" in a half-word. The S9(9) is probably "far over the top" as per range of possible values, but such things concern Programmer 1 not at all.
Probably Programmer 2 had concerns about using an S9(9) COMP for something requiring (perhaps many) fewer than 9999 "things". "I'll be 'efficient' without changing the existing code". It seems to me unlikely that the field was ever defined as unsigned.
A COMP/COMP-4 with nine digits does have a performance penalty when used for calculations. Try "ADD 1" to a 9(9) and a 9(8) and a 9(10) and compare the generated code. If you can have nine digits, define with 9(10), otherwise 9(8), if you need a fullword.
Programmer 2 knows something of this.
The COMPUTE with + 0 is probably deliberate. Why did Programmer 2 use the COMPUTE like that (the original question)?
Now it is going to get complicated.
There are two "types" of "binary" fields on the Mainframe: those which will contain values limited by the PICture clause (USAGE BINARY, COMP and COMP-4); those which contain values limited by the field size (USAGE COMP-5).
With BINARY/COMP/COMP-4, the size of the field is determined from the PICture, and so are the values that can be held. PIC 9(4) is a halfword, with a maxiumum value of 9999. PIC S9(4) a halfword with values -9999 through +9999.
With COMP-5 (Native Binary), the PICture just determines the size of the field, all the bits of the field are relevant for the value of the field. PIC 9(1) to 9(4) define halfwords, pic 9(5) to 9(9) define fullwords, and 9(10) to 9(18) define doublewords. PIC 9(1) can hold a maximum of 65535, S9(1) -32,768 through +32,767.
All well and good. Then there is compiler option TRUNC. This has three options. STD, the default, BIN and OPT.
BIN can be considered to have the most far-reaching affect. BIN makes BINARY/COMP/COMP-4 behave like COMP-5. Everything becomes, in effect, COMP-5. PICtures for binary fields are ignored, except in determining the size of the field (and, curiously, with ON SIZE ERROR, which "errors" when the maxima according to the PICture are exceeded). Native Binary, in IBM Enterprise Cobol, generates, in the main, though not exclusively, the "slowest" code. Truncation is to field size (halfword, fullword, doubleword).
STD, the default, is "standard" truncation. This truncates to "PICture". It is therefore a "decimal" truncation.
OPT is for "performance". With OPT, the compiler truncates in whatever way is the most "performant" for a particular "code sequence". This can mean intermediate values and final values may have "bits set" which are "outside of the range" of the PICture. However, when used as a source, a binary field will always only reflect the value specified by the PICture, even if there are "excess" bits set.
It is important when using OPT that all binary fields "conform to PICture" meaning that code must never rely on bits which are set outside the PICture definition.
Note: Even though OPT has been used, the OPTimizer (OPT(STD) or OPT(FULL)) can still provide further optimisations.
This is all well and good.
However, a "pickle" can readily ensue if you "mix" TRUNC options, or if the binary definition in a CALLing program is not the same as in the CALLed program. The "mix" can occur if modules within the same run-unit are compiled with different TRUNC options, or if a binary field on a file is written with one TRUNC option and later read with another.
Now, I suspect Programmer 2 encountered something like this: Either, with TRUNC(OPT) they noticed "excess bits" in a field and thought there was a need to deal with them, or, through the "mix" of options in a run-unit or "across file usage" they noticed "excess bits" where there would be a need to do something about it (which was to "remove the mix").
Programmer 2 developed the COMPUTE A = B + 0 to "deal" with a particular problem (perceived or actual) and then applied it generally to their work.
This is a "guess", or, better, a "rationalisation" which works with the known information.
It is a "fake" fix. There was either no problem (the normal way that TRUNC(OPT) works) or the correct resolution was "normalisation" of the TRUNC option across modules/file use.
I do not want loads of people now rushing off and putting COMPUTE A = B + 0 in their code. For a start, they don't know why they are doing it. For a continuation it is the wrong thing to do.
Of course, do not just remove the "+ 0" from any of these that you find. If there is a "mix" of TRUNCs, a program may stop "working".
There is one situation in which I have used "ADD ZERO" for a BINARY/COMP/COMP-4. This is in a "Mickey Mouse" program, a program with no purpose but to try something out. Here I've used it as a method to "trick" the optimizer, as otherwise the optimizer could see unchanging values so would generate code to use literal results as all values were known at compile time. (A perhaps "neater" and more flexible way to do this which I picked up from PhilinOxford, is to use ACCEPT for the field). This is not the case, for certain, with the code in question.
I wonder if a testing version of the sources ever had
COMPUTE WS-SUB = I + 0
ON SIZE ERROR
DISPLAY "WS-SUB overflow"
STOP RUN
END-COMPUTE
with the range test discarded when the developer was satisfied and cleaning up? MOVE doesn't allow declarative SIZE statements. That's as much of a reason as I could see. Or perhaps developer habit of using COMPUTE to move, as a subtle reminder to question the need for defensive code at every step? And perhaps not knowing, as Joe pointed out, the SIZE clause would be just as effective without the + 0? Or a maintainer struggled with off by one errors and there was a corrective change from 1 to 0 after testing?