Hello all,
almost every Natural-Programmer knows the weird behaviour of COMPUTE ROUNDED.
define data local
1 #five (I1) CONST <5>
1 #three (I1) CONST <3>
1 #p2 (P1.3)
end-define
compute rounded #p2 = #five / #three
write '=' #p2 /* results in 1.000
end
There’s an easy way to get 1.667 as a result. Just add 0.0 to the divisor. I don’t know exactly how it works. But it does.
Try this:
define data local
1 #five (I1) CONST <5>
1 #three (I1) CONST <3>
1 #p1 (P1.3)
1 #p2 (P1.3)
1 #p3 (P1.3)
end-define
compute rounded #p1 = 5 / 3
compute rounded #p2 = #five / #three
compute rounded #p3 = (#five + 0.0) / #three
write '=' #p1 / '=' #p2 / '=' #p3
end
Regards
Matthias
Hi Matthias,
Nothing “weird” about what Natural does. Basically, Natural follows the way mathematics does arithmetic.
In short, you cannot create precision by performing an arithmetic operation.
Suppose I reach into my pocket and pull out a five dollar bill. I also can feel some coins in the pocket but I do not take them out. I want to divide ALL my money into three “groups”. However, all I know is that to the nearest dollar, I have five dollars. Is the “answer” 1.667? no. It is something greater than that.
Way back in school we “learned” how to do long division of five by three. Three goes into five once, so write the one above the line, multiply three by the one, then subtract three from five, producing 2, and “bring down” a zero (really, what zero?? it was usually called an imaginary zero when I went to school). Now divide 20 by three. The result is six, and so forth.
This is wrong. Ask any engineer. You cannot divide a number that is only correct to the nearest integer and produce an answer that is correct to three decimal places.
If #five was measured to three decimal places , P1.3, Natural would give you the answer 1.666 or 1.667 depending on whether rounded or truncated was specified, which is correct by the strict rules of mathematics.
Sorry, but I taught mathematics a long time ago, and old habits die hard.
Hi Matthias,
that’s the “normal” Natural behavior. If you divide like I1/I1 the intermediate result will also be an I1. Thus 5/3 is 1 as (I1). The rounded and (P1.3) comes too late
Your approach, to add a “0.0”, can be seen as a more general approach. It changes the format of the intermediate result.
I use the same approach, when I multiply an (I4) and expect a result which might overflow. So I force a (P19) or (N19) (can’t say exactly which but it uses 19 digits):
#I4 * 0000000000268435456
Means, I just add the zeros in front to force a longer intermediate value.
Regards
Lukas
Yes, I know the documentation and the explanation of the “intermediate result”. But I don’t know, why the constant 0.0 changes the precision to whatever it takes. Maybe it changes it to F8 internally?
Hi Steve,
I’m talking from a programmers point of view.
compute rounded #p1 = 5 / 3
compute rounded #p2 = #five / #three
compute rounded #p3 = (#five + 0.0) / #three
write '=' #p1 / '=' #p2 / '=' #p3
#P1: 1.667
#P2: 1.000
#P3: 1.667
And I still think this is kinda weird - espacially for a non-natural programmer. I would expect, that the result variable defines the precision of the result. That’s the behaviour of the other programming languages I know.
But everything is OK so far. I know this trap for many years. And I got a workaround by adding 0.0 to the divisor. That’s also a bit weird, isn’t it?