Page 1 of 8

issue-#124 Range-check for SHORT(ENTIER(real))

Posted: Thu Aug 18, 2016 8:02 pm
by Robert
With the code below I am trying to create a random 32-bit SET from a random REAL in the range [0 .. 1).

I know that I am using SHORT to type convert an out of range LONGINT, but I thought that SHORT did not do range checking. However this code TRAPs at run time.

Maybe there is a good correct solution. I can immediately think of three possiblities:
- Replace SHORT by SYSTEM.VAL
- Subtract 1/2 from r
- Use the empty code procedure (the added '~' is there to fool phpBB!)

Code: Select all

PROCEDURE [co~de] Low* (m : LONGINT) : INTEGER;
I haven't yet actually tried any of these!
[Postscript: I have now tried the "Low" option, which I prefer, and it works.]

My point is that "s" is the correct result that I want, but "t" causes a TRAP.
Surely one should expect the expressions for both "s" & "t" to behave the same - I think this difference is a bug.

Code: Select all

PROCEDURE  RandomSet*;
  CONST
    twoPwr  =  4294967296.;	(*  2^32  *)
  VAR
    r:  REAL; m:  LONGINT; s, t:  SET;
  BEGIN
      r  :=  0.999999;

      m  :=  ENTIER (r * twoPwr);
      s  :=  BITS (SHORT (m));

      t  :=  BITS (SHORT (ENTIER (r * twoPwr)))
  END  RandomSet;

Re: Compiler arithmetic error ?

Posted: Fri Aug 19, 2016 9:22 am
by Josef Templ
It seems that ENTIER is always checked.
Assigning to LONGINT first does not generate a trap in the example code
because ENTIER is OK and SHORT is without a range check.
If done in a single statement, an FPU instruction is used for
converting from REAL to INTEGER directly and that instruction does a check.
Surprising, indeed, but not possible to fix.
(IMHO, using the FPU for random numbers is not a good idea anyway because it can produce
strange results such as NaN or infinity easily.)

By the way, there is a missing part in the docu of Kernel:
Trap 143 uses Kernel.val but this is not documented.
In this case, Kernel.val encodes two 16-bit values, the FPU control word and the FPU status word.
These are the two values displayed in the trap window (the control word comes first).
By inspecting the status word it can be figured out which kind of exception occured.
In this example, I think, it is a Precision exception (bit 5 is set in both words).

In addition, trap 144 (Not a number) is missing.
In addition, ...
The (err, val) table needs to be aligned with DevDebug.Trap.

- Josef

Re: Compiler arithmetic error ?

Posted: Fri Aug 19, 2016 10:18 am
by Robert
Josef Templ wrote:IMHO, using the FPU for random numbers is not a good idea anyway because it can produce
strange results such as NaN or infinity easily.
I don't quite understand your concern here.
In my real code I am getting (pseudo)random REALs, in the range (0 .. 1), by calling the external dll ACML - the AMD Core Maths Library.
This is a very useful library provided by AMD, whose main feature, as far as I am concerned, is the FORTRAN libraries LAPACK & BLAS, which provide efficient advanced matrix operations.
I use the AMD implementation of the "Mersenne Twister" random number generator; it has a very good reputation.

Re: Compiler arithmetic error ?

Posted: Fri Aug 19, 2016 10:35 am
by Josef Templ
I thought that you are trying to generate random numbers by means of
doing repeated computations on reals and then converting to INTEGER and SET.
Random numbers are normally generated with integer operations (MOD wordsize)
and then converted to reals (0..1) or whatever format you need.
If you use an external library for that you must of course use what you get.

Re: Compiler arithmetic error ?

Posted: Fri Aug 19, 2016 11:32 am
by luowy
it's out of range trap.
ENTIER(x) convet real to longint,which require x in a range between MIN(LONGINT)..MAX(LONGINT);
but SHORT(ENTIER(x)) convert real to integer directly,which require x in a range between MIN(INTEGER)..MAX(INTEGER);
the SHORT(real) use float instuction and the SHORT(longint) use a common move instruction;

Re: Compiler arithmetic error ?

Posted: Fri Aug 19, 2016 11:45 am
by Robert
I have probably changed my mind about this being a bug.

SHORT : LONGINT → INTEGER is defined in the Report (Section 10.3) as the "identity" function.

It goes without saying that this does not apply where it is impossible.
Hence it is NOT defined for out-of-range values, and we should have no expectations as to its behaviour, including any expectation of consistency.


It is interesting to apply this logic to the previous line in the Report:

ORD : SET → INTEGER is defined as "(SUM i: i IN x: 2^i)" which is also impossible for the SET {31} as this sum exceeds MAX(INTEGER).

I have no reason to suppose ORD does not behave as we informally expect, so I propose changing this definition
from:
(SUM i: i IN x: 2^i)
to
SUM i: i IN x: ±2^i, + used for i ≤ 30

Re: Compiler arithmetic error ?

Posted: Sat Aug 20, 2016 5:25 am
by Josef Templ
The original definition of ORD is subtle, simple, and correct.

You can assume LONGINT arithmetics for computing SUM.
Since ORD returns INTEGER instead of LONGINT it implies an outermost SHORT.
This leads to a negative number if the sign bit (31) is set.

If INTEGER arithmetics is assumed, it is also correct because
all operations are done MOD 2^32 using two's complement representation.
This is actually what happens inside.
There is no code at all required for this operation but the bits are
treated as a two's complement representation of a number.

- Josef

Re: Compiler arithmetic error ?

Posted: Sat Aug 20, 2016 8:09 am
by Robert
Josef Templ wrote:You can assume LONGINT arithmetics for computing SUM.
Since ORD returns INTEGER instead of LONGINT it implies an outermost SHORT.
That is not how I read it. To me "SUM i: i IN x: 2^i" is not using computer operations; it is using mathematical operations to explain computer operations, in this case ORD.

And anyway, the main topic of this thread is the two points:
- SHORT is not defined for out-of-range inputs
- and it doesn't always behave as required here.

I don't feel strongly about this, and expect reluctance to any changes to the Report, so it is ok by me to move on.

Re: Compiler arithmetic error ?

Posted: Sat Aug 20, 2016 3:01 pm
by luowy
a fixup for

Code: Select all

t := BITS(SHORT(ENTIER(r * twoPwr)));  (*trap*)
DevCPB.Convert

Code: Select all

...
    ELSIF (x.class = Nmop) & (x.subcl = conv) & (DevCPT.Included(f, x.left.typ.form) OR DevCPT.Included(f, g)
        (*>>>*)&(x.left.typ.form # Real64) (*<<<*) )
   THEN
	(* don't create new node *)
...

Re: Compiler arithmetic error ?

Posted: Sun Aug 21, 2016 9:31 am
by Josef Templ
The problem is that it changes the behavior of SHORT(ENTIER).
Until now SHORT(ENTIER) was range checked but with the change it is not.
You are eliminating a runtime check and this is a severe change
that in my opinion is not justified and potentially harmful.
I am strongly against such a change.

- Josef