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

The features that we decide to not apply in the current time
Post Reply
User avatar
Robert
Posts: 1024
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

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

Post 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;
User avatar
Josef Templ
Posts: 2047
Joined: Tue Sep 17, 2013 6:50 am

Re: Compiler arithmetic error ?

Post 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
User avatar
Robert
Posts: 1024
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: Compiler arithmetic error ?

Post 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.
User avatar
Josef Templ
Posts: 2047
Joined: Tue Sep 17, 2013 6:50 am

Re: Compiler arithmetic error ?

Post 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.
luowy
Posts: 234
Joined: Mon Oct 20, 2014 12:52 pm

Re: Compiler arithmetic error ?

Post 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;
User avatar
Robert
Posts: 1024
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: Compiler arithmetic error ?

Post 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
User avatar
Josef Templ
Posts: 2047
Joined: Tue Sep 17, 2013 6:50 am

Re: Compiler arithmetic error ?

Post 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
User avatar
Robert
Posts: 1024
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: Compiler arithmetic error ?

Post 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.
luowy
Posts: 234
Joined: Mon Oct 20, 2014 12:52 pm

Re: Compiler arithmetic error ?

Post 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 *)
...
User avatar
Josef Templ
Posts: 2047
Joined: Tue Sep 17, 2013 6:50 am

Re: Compiler arithmetic error ?

Post 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
Post Reply