Slow, I know, but I think I've just got to why you've defined everything with 15 decimal places. You couldn't get it to work otherwise.
Read the question in the link lower down (and the answer, of course). You do not need to specify all fields with the precision you require for the output.
Re-arrange your COMPUTE. Exponentiation outside the main COMPUTE. Multiply first. Then divide. Any additions/subtractions fit in naturally. Use parenthesis to exactly specify how you want a human to read the COMPUTE (the compiler doesn't care, it'll do what it is told, but at times people don't know what they are telling it).
If you do this (correctly) you will get the same answer as in your COMPUTE with all fields having 15 decimal places.
If you don't do this, your COMPUTE (and others when you copy it) will always be fragile and prone to error when changed.
It was a good idea to break out the COMPUTE into smaller ones like you did so that you could see which values to put into your calculator. You can do the same thing when you make the fields their correct sizes.
I'm going to have to totally re-write this, as the multiple updates are making it messy... at some point.
OK, confirmed. The difference is due to the calculation of a non-integer exponentiation within the COMPUTE which, as the manual says, then converts everything in the COMPUTE (all the intermediate fields) into floating-point numbers, which have a higher number of decimal places than the 15 specified in the PICture clauses.
There is now a diagnostic message (having taken the exponentiation out) due to the multiplication, which would like to have 36 digits, but can only have 30 (ARITH(COMPAT)) or 31 (ARITH(EXTEND)). If high-order data is truncated through this, there will be a run-time message.
Note. With ARITH(COMPAT) 15 is the largest number of significant digits where precision will not be lost (64-bit floating-point). ARITH(EXTEND) guarantees precision, but there is an overhead in processing (128-bit floating-point).
Back to earlier...
Been thinking more about this. You are using 18 digits, and you haven't mentioned using ARITH(EXTEND) as a compile option and haven't mentioned any diagnostic messages being produced for the large COMPUTE. Which is interesting.
Haven't done much exponentiation in COBOL, and then only with whole numbers. So I looked at the manual. Because of the fractional exponentiation everything in your large COMPUTE is being done in floating-point. That doesn't matter as such, but it means things are being done with greater precision than is expected from the 15 decimals in your definition. In your small COMPUTEs, this is not happening.
I'd suggest taking the exponentiation out of the big COMPUTE, calculating that separately and simply putting that result in the big COMPUTE (a simple addition replacing the exponentiation). I suspect at that stage the compiler will start to moan about the number of significant digits in results. If it does, then you will get a run-time message if you actually lose a significant digit.
You should:
- Take the exponentiation out of the big COMPUTE and replace it with the result of a separate COMPUTE of the exponentiation
- Define each field to its maximum size required by the data (not the maximum possible for everything)
- (Probably) change to COMP-3 from COMP, but test it yourself
- Parenthesise everything so that the human reader knows the order the compiler will do things in
- If you still have warnings about possible truncation in the COMPUTE, look at ARITH(EXTEND) compiler option, but don't just put it in as a fix, only use it if you need it, and document its use for that program
I will try to confirm this later, but I think that will sort it out.
The following was the start, and still applies in general, although not directly relevant for the specific question (the problem being the higher floating-point precision forced onto everything vs only forced for the exponentiation):
Your problem with the small COMPUTEs is that you are not executing them in the same order as the elements of the large COMPUTE.
The (
and )
are not there for fun, or just to group things together, they establish precedence in the calculations.
What else establishes precedence? The operator used. What is the order of precedence? Well, you have to look that up in the manual, memorise it, or familiarise yourself with it each time if you forget. Mmmmm.... not a good suggestion.
Plus, other people will be working on the programs that you write or change. And they may "know" how a COMPUTE works (by which I mean they don't, but think they do, so won't look it up). Doubly-not-good suggestion.
So....
Use (
and )
and define the order in which you want things done.
Also be aware of where you may lose significance. Have a look at this one, AS/400: Using COMPUTE function, inconsistent results with different field definition, read up and understand the referenced parts of the Enterprise COBOL manuals.
As a summary of the linked-to question on this site, multiply first and divide last, to ensure that intermediate results do not lose significant digits. Unless you deliberately want to lose digits, in which case do those COMPUTEs to lose significance individually, and comment the code, so that no-one "fixes" it.
Also it is unusual on the Mainframe to use COMP/COMP-4/BINARY/COMP-5 for fields with decimal places. Once you are happy with your COMPUTEs, copy the program and change the field definitions to COMP-3/PACKED-DECIMAL. Put a loop on a counter in each program, and see if you notice any significant difference in CPU usage.