A REAL bad program compiles well

Programming language questions
User avatar
adimetrius
Posts: 68
Joined: Sun Aug 04, 2019 1:02 pm

A REAL bad program compiles well

Post by adimetrius »

Colleagues,

Code: Select all

   PROCEDURE Really*;
      VAR s: SHORTREAL; r: REAL;
   BEGIN s := -0.4523987; r := -0.4523987; Log.Real(s); Log.Char(' '); Log.Real(r)
   END Really;
(* output:  -0.4523986876010895  -0.4523987 *)
As far as I understand, -0.4523987 cannot be represented in the 4-byte format. In this case, I would regard s := -0.4523987 to be a bad program, and expect an error message from the compiler. Just as if i: INTEGER then i := MAX(INTEGER) + 1 is a bad program, and if sh: SHORTCHAR then sh := 100X is a bad program, and both are regarded by the compiler as such.

However, I don't have any experience with REAL numbers. Is my expectation wrong? The Language reports states of literals:
LR, 3. Vocabulary and representation wrote:A real number is always of type REAL
User avatar
Robert
Posts: 177
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: A REAL bad program compiles well

Post by Robert »

adimetrius wrote:Colleagues,
As far as I understand, -0.4523987 cannot be represented in the 4-byte format.
Correct; the closest REAL number is 0.452398699999999986953724828708800487220287322998046875 (exactly).
The closest SHORTREAL number is 0.4523986876010894775390625 (exactly).

A simpler example is 0.3 which, as a REAL, actually becomes 0.299999999999999988897769753748434595763683319091796875, which is an error of about 11.10223 × 10↑-18.

REAL only claims to give about 16 or 17 decimal places accuracy. SHORTREAL only gives 6 or 7.

It would be a very inconvenient restriction to allow only exactly representable numbers to be legal. Every language I know regards making a good approximations for REALs and SHORTREALs to be acceptable; ie not a programming error.


Out of range INTEGERs are different; they are (or should be!) unacceptable.
Last edited by Robert on Tue Jan 05, 2021 8:07 pm, edited 2 times in total.
cfbsoftware
Posts: 55
Joined: Wed Sep 18, 2013 10:06 pm
Contact:

Re: A REAL bad program compiles well

Post by cfbsoftware »

FYI I checked your example with the Gardens Point Component Pascal compiler

and it gave the error message:

RealTest.cp(8,7) : error : Expression not assign-compatible with destination
RealTest.cp(8,7) : error : LHS type was SHORTREAL, RHS type was REAL

When the procedure was changed to

Code: Select all

   PROCEDURE Really*;
      VAR s: SHORTREAL; r: REAL;
   BEGIN 
    s := SHORT(-0.4523987);
    r := -0.4523987; 
    Out.Real(s, 10); 
    Out.Char(' '); 
    Out.Real(r, 10)
   END Really;
it compiled OK and the resulting output was

Code: Select all

-0.452398687601089 -0.4523987
To see how other languages behave, the following C# code is equivalent to the Component Pascal code that was generated:

Code: Select all

public static void Really()
{
	float s = (float)-0.4523987;
	double r = -0.4523987;
	Out.Real((double)s, 10);
	Out.Char(' ');
	Out.Real(r, 10);
}
User avatar
Robert
Posts: 177
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: A REAL bad program compiles well

Post by Robert »

Code: Select all

  VAR   x  :  SHORTREAL;
  BEGIN
    x  :=  0.3
It looks like this code compiles ok in BlackBox, but not in Gardens Point.

As I read the language report "0.3" is a real (see section 3.2).
This section also says
A real number is always of type REAL.
so it looks like a BlackBox compiler error?

BUT I much prefer the BlackBox behaviour!

Appendix A says
If a real constant x with |x| <= MAX(SHORTREAL) or x = INF is combined with a nonconstant operand of type SHORTREAL, the constant is considered a SHORTREAL and the result type is SHORTREAL.
I don't think this would make much sense if the concept of SHORTREAL constant was not supported, but I can't find this explicitly in the report.
User avatar
adimetrius
Posts: 68
Joined: Sun Aug 04, 2019 1:02 pm

Re: A REAL bad program compiles well

Post by adimetrius »

Colleagues,
thank you for your clarifications.

From the persceptive of strict LR compliance, it makes sense to me why GPCP requires the explicit conversion: shortreal := SHORT(0.3)
It seems that, interpreted as is on the face, the LR renders the following as not Assignment Compatible:
shortreal := 0.3
LR App. A, Assignment compatible wrote: 2. Te and Tv are numeric or character types and Tv includes Te;
Te = REAL, Tv = SHORTREAL, => shortreal and 0.3 are not assignment compatible.

But definitely shortreal := 0.3 it is more convenient than shortreal := SHORT(0.3).

Maybe the LR could be amended and brought in line with the more convenient compiler behavior - and with itself in the Assignment Compatible section. Maybe an amended clause for reals like the existing one for integers:
LR 3.2 wrote:The type of an integer constant is INTEGER if the constant value belongs to INTEGER, or LONGINT otherwise (see 6.1).
=> The type of a real constant is SHORTREAL if the constant value belongs to SHORTREAL, or REAL otherwise (see 6.1).
('belongs' however seems to ignore precision errors; so a REAL literal in program text with 35 fraction digits could be treated by a LR implementation as a SHORTREAL if it belonged to the SHORTREAL range. Maybe 'could be represented without precision loss' rather than 'belongs'? idonno)

De-facto, the compiler in BlackBox does in fact treat real constants that are in the SHORTREAL range AND don't loose precision in 4-byte format as SHORTREALs - it performs the conversion to 4-byte format and allocates the 4-byte literal in the constants section of the MetaBlk of the OCF format (cf. DevCPL486.AllocConst). (Of course, most reals loose precision in 4-byte format, so I think only rare cases like 3.0 would fall under this small optimization provision.)

Again, I don't have any REAL applications, and don't have a perspective on what's convenient or makes sense in applications; I came across this as I was working to implement REALs in Herschel. My primary concern is LR compliance.
User avatar
Robert
Posts: 177
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: A REAL bad program compiles well

Post by Robert »

adimetrius wrote: The type of a real constant is SHORTREAL if the constant value belongs to SHORTREAL, or REAL otherwise (see 6.1). .
While I agree that the Language Report does not seem to clearly describe the BBox compiler behaviour (and I don't want the behaviour changed) the above suggestion does not capture the (deliberately) ambiguous behaviour of the compiler.
Consider

Code: Select all

PROCEDURE  Do*;
  CONST
    k  =  1. / 3.;
  VAR
    s  :  SHORTREAL;
    r  :  REAL;
  BEGIN
    s  :=  k;
    r  :=  k;
    Out.Real (s, 15); Out.Ln;
    Out.Real (r, 15); Out.Ln;
  END  Do;

Results:
0.3333333432674408
0.3333333333333333
k both behaves like a SHORTREAL as it can be assigned to s, and as a REAL as it has 64 bits precision when assigned to r.

A true story - apologies if I have misremembered some of the details of about 20 years ago ....
I had some code rather like:

Code: Select all

CONST
  pi* = 3.14159265358979323846;
  rad2deg* = 180. / pi;
I used rad2deg to convert angles in radians to degrees, and wanted to use it in both SHORTREAL and REAL expressions, and not loose precision when I didn't have to.
There was some problem prior to BlackBox 1.2 (maybe CONSTs couldn't be exported - I forget exactly what), but this capability was introduced at that time, and there was some description in some documentation - maybe the release notes - of this dual character of real constants.

But version 1.2 (was it still Oberon/F then?) introduced a curious feature. Within the defining module all was well, but in importing modules rad2deg could only be one type which was determined by its first use.

I immediately wrote a complaining email to oms saying I disliked this decision, and it had broken backward compatibility of some of my code. They said it was not a decision, but an error, which they quickly fixed by releasing version 1.2.1.

So, while this ambiguous behaviour might not be clearly described in the Language Report, it is both deliberate, and, in my opinion, convenient.
User avatar
adimetrius
Posts: 68
Joined: Sun Aug 04, 2019 1:02 pm

Re: A REAL bad program compiles well

Post by adimetrius »

So, are you saying you don't want to lose precision? Your story helps understand how it is very convenient to have constants that can be used with appropriate precision in REAL and SHORTREAL expressions. How about the other wording then - would it capture what you want to achieve (keeping flixibility) while also clearing the ambiguity?

The type of a real number is SHORTREAL if the number belongs to SHORTREAL and can be represented as a SHORTREAL without precision loss, or REAL otherwise.

I've gone from constant to number to stress that it's not talking about named constants (which it isn't in section 3), but rather unnamed literal numbers. The named constant type derivation would be governed by other passages in the LR - the appendices, I guess.

P.S. Version 1.2. would be more than 20 yrs ago... Time flies, i know :lol:
User avatar
Robert
Posts: 177
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: A REAL bad program compiles well

Post by Robert »

Assignment compatible
An expression e of type Te is assignment compatible with a variable v of type Tv if one of the following conditions hold:
...
5. Tv is a numeric type and e is a constant expression whose value is contained in Tv;
I think the quote above (from the Language Report) allows

Code: Select all

  CONST
    k  =  1. / 3.;
  VAR
    s  :  SHORTREAL;
    r  :  REAL;
  BEGIN
    s  :=  k;
    r  :=  k;
and if Gardens Point insists on writing s := SHORT (k) it is wrong.

I don't know if people think this is inconsistent with "A real number is always of type REAL." Maybe it would be better to simply delete this sentance, but I don't have strong views on the subject.
User avatar
Robert
Posts: 177
Joined: Sat Sep 28, 2013 11:04 am
Location: Edinburgh, Scotland

Re: A REAL bad program compiles well

Post by Robert »

Robert wrote: ... (The Language Reoprt says) "A real number is always of type REAL." Maybe it would be better to simply delete this sentance, but I don't have strong views on the subject.
I have changed my mind!

Code: Select all

CONST
  a  =  100000. / 3. - 33333.;


PROCEDURE Rnd (x : REAL) : SHORTREAL;
  VAR
    s  :  SHORTREAL;
  BEGIN
    s  :=  SHORT (x); RETURN  s
  END  Rnd;


PROCEDURE  Do*;
  VAR
    b, u, v  :  SHORTREAL;
    c, d, t  :  REAL;
  BEGIN
    b  :=  a;
    c  :=  Rnd (a);

    u  :=       100000. / 3.  - 33333.;
    v  :=  Rnd (100000. / 3.) - 33333.;

    t  :=  100000.;
    t  :=            t  / 3.  - 33333.;

 
    Out.Ln;
    Out.String ('a  - CONST :  '); Out.Real (a, 15); Out.Ln;
    Out.String ('b  - SHORT :  '); Out.Real (b, 15); Out.Ln;
    Out.String ('c  - REAL  :  '); Out.Real (c, 15); Out.Ln;

    Out.Ln;
    Out.String ('u  - SHORT  :  '); Out.Real (u, 15); Out.Ln;
    Out.String ('v  - SHORT  :  '); Out.Real (v, 15); Out.Ln;
    Out.Ln;
    Out.String ('t  - REAL  :  '); Out.Real (t, 15); Out.Ln
  END  Do;

Code: Select all

Results:

a  - CONST :  0.3333333333357587
b  - SHORT :  0.3333333432674408
c  - REAL  :  0.3333333432674408

u  - SHORT  :  0.3333333432674408
v  - SHORT  :  0.33203125

t  - REAL  :  0.3333333333333321
In this example I evaluate 100000 / 3 - 33333. The exact answer is 1 / 3. The example gives 4 different inexact results.

a - This uses CONSTant, 64-bit arithmetic, and has 5 incorrect digits.
b - This is a SHORTREAL using a constant expression, and is correct to 7 digits, the best one can hope for.
c - Is the same, but in a REAL variable - basically this is testing the Rnd function!

u - A SHORTREAL using an in-line constant expression. Good result for a SHORTREAL.
v - A SHORTREAL using 32-bit shortreal arithmetic throughout. Bad result, only 2 good digits.

t - A REAL using in-line 80-bit real arithmetic. Best result, only 2 bad digits.

The requirement that (literal) numbers are REAL is there to ensure that SHORTREAL arithmetic is not used to evaluate (constant) expressions even if all the inputs, and the result, are used as short reals.
User avatar
adimetrius
Posts: 68
Joined: Sun Aug 04, 2019 1:02 pm

Re: A REAL bad program compiles well

Post by adimetrius »

Assignment compatible
An expression e of type Te is assignment compatible with a variable v of type Tv if one of the following conditions hold:
...
5. Tv is a numeric type and e is a constant expression whose value is contained in Tv;
Thanks for pointing this out.

What does 'contained' mean? Is it ∈?
byte := 1;
byte: BYTE; 1: INTEGER (according to 3.2); 1 ∈ [0..255] => byte and 1 are assignment compatible according to (5).

short := 1. / 3.
short: SHORTREAL; 1./3.: REAL (according to 3.2); 1./3. ∈ [MIN(SHORTREAL)..MAX(SHORTREAL)] => short and 1./3. are assignment compatible according to (5).

Is this how you also interpret 'contained'? And are you saying this should be regarded as correct despite the precision loss?
Post Reply