Lazarus

Free Pascal => General => Topic started by: Roland57 on May 14, 2021, 05:51:07 pm

Title: How to force the not operator to return a byte
Post by: Roland57 on May 14, 2021, 05:51:07 pm
Hello!

I have the following code:

Code: Pascal  [Select][+][-]
  1. const
  2.   a = 128;
  3.   b =  64;
  4.   c = byte(not(a or b));
  5.  
  6. begin
  7. end.

With FPC 3.2.0, I get this warning; "Warning: range check error while evaluating constants (-193 must be between 0 and 255)"

(With FPC 3.0.4, I didn't get any warning. I don't know why.)

How could I get rid of the warning? I tried several things but didn't find the solution.

Regards.

Roland
Title: Re: How to force the not operator to return a byte
Post by: winni on May 14, 2021, 06:04:15 pm
Hi!

If you want to get a correct result and no warning do this:

Code: Pascal  [Select][+][-]
  1.     const
  2.       a = byte(128);
  3.       b =  byte(64);
  4.       c = byte(not(a or b));
  5.      
  6.     begin
  7.     end.

Cast both const to a byte to the range of 0..255. Const b is now only in the range 0..64 and so only 7 bits while  128 is 8 bits..

Winni
Title: Re: How to force the not operator to return a byte
Post by: MarkMLl on May 14, 2021, 06:08:09 pm
Try

Code: Pascal  [Select][+][-]
  1.     const
  2.       a: byte= 128;
  3.       b: byte=  64;
  4.       c { : byte } = not(a or b);
  5.      
  6.     begin
  7.     end.
  8.  

If that doesn't work try byte(a) etc., i.e. to make it absolutely explicit that you're not expecting it to be extended.

MarkMLl
Title: Re: How to force the not operator to return a byte
Post by: howardpc on May 14, 2021, 06:09:28 pm
try
Code: Pascal  [Select][+][-]
  1. const
  2.   a = ShortInt(128);
  3.   b = 64;
  4.   c = Byte(not(a or b));
Title: Re: How to force the not operator to return a byte
Post by: Roland57 on May 14, 2021, 07:04:15 pm
Thank you all for your answers.

@howardpc

Your proposition seems to solve the problem, but I don't understand it.  :)
Title: Re: How to force the not operator to return a byte
Post by: MarkMLl on May 14, 2021, 07:19:16 pm
Your proposition seems to solve the problem, but I don't understand it.  :)

Neither do I, since according to https://www.freepascal.org/docs-html/current/ref/refsu4.html#x26-250003.1.1 the largest ShortInt is 127.

MarkMLl
Title: Re: How to force the not operator to return a byte
Post by: lucamar on May 14, 2021, 07:45:12 pm
Your proposition seems to solve the problem, but I don't understand it.  :)
Neither do I, since according to https://www.freepascal.org/docs-html/current/ref/refsu4.html#x26-250003.1.1 the largest ShortInt is 127.

The quid of the question is that ShortInt forces the constant to be interpreted as/converted to a signed byte. To be fair, though, casting to Byte should work equally well (or better).
Title: Re: How to force the not operator to return a byte
Post by: Roland57 on May 14, 2021, 08:18:10 pm
To be fair, though, casting to Byte should work equally well (or better).

Should, maybe, but doesn't.  :)

Code: Pascal  [Select][+][-]
  1. const
  2.   a = byte(128);
  3.   b = 64;
  4.   c = byte(not(a or b));
  5.  
  6. begin
  7. end.

Quote
Warning: range check error while evaluating constants (-193 must be between 0 and 255)
Title: Re: How to force the not operator to return a byte
Post by: winni on May 14, 2021, 08:46:33 pm
Hi!

Solution is in reply #1 above.

Code: Pascal  [Select][+][-]
  1. b = byte(64);

Winni
Title: Re: How to force the not operator to return a byte
Post by: Roland57 on May 14, 2021, 09:25:33 pm
Solution is in reply #1 above.

Thanks, but...

Quote
Warning: range check error while evaluating constants (-193 must be between 0 and 255)

 :-\
Title: Re: How to force the not operator to return a byte
Post by: winni on May 14, 2021, 10:06:28 pm
Hi!

Another reason to turn warnings off:

Code: Pascal  [Select][+][-]
  1. Unit HelterSkelter;
  2. {$warnings off}
  3.  
Winni
Title: Re: How to force the not operator to return a byte
Post by: Roland57 on May 14, 2021, 10:13:17 pm
Another reason to turn warnings off:

Yes, this is a also a solution.  :)
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 14, 2021, 10:35:28 pm
Your proposition seems to solve the problem, but I don't understand it.  :)

Neither do I, since according to https://www.freepascal.org/docs-html/current/ref/refsu4.html#x26-250003.1.1 the largest ShortInt is 127.

MarkMLl

ShortInt(128) = -128
and
Code: Pascal  [Select][+][-]
  1. const
  2.   a = -128;
  3.   b = 64;
  4.   c = not(a or b);
  5.  
  6. begin
  7.   writeln(c);
  8. end.  
outputs 63.
While
Code: Pascal  [Select][+][-]
  1. const
  2.   a = 128;
  3.   b = 64;
  4.   c = not(a or b);
  5.  
  6. begin
  7.   writeln(c);
  8. end.  
outputs -193.
Why FPC 3.2.0 gives warning at explicit casting -193 to byte, is another question... ;)
Title: Re: How to force the not operator to return a byte
Post by: MarkMLl on May 14, 2021, 10:59:40 pm
Why FPC 3.2.0 gives warning at explicit casting -193 to byte, is another question... ;)

In retrospect, I rather wish I'd not got involved in this :-)

From playing around a few minutes ago, I suspect that the bitwise operators aren't as well implemented at compilation time as we're assuming:

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. const
  6.   a: byte= 128;
  7.   b: byte= 64;
  8.   c= { not } a or b; <== test.pas(8,20) Error: Illegal expression
  9.  
  10. begin
  11. end.
  12.  

My first thought was that {$WRITEABLECONST OFF}  might help, but no such luck.

MarkMLl
Title: Re: How to force the not operator to return a byte
Post by: winni on May 14, 2021, 11:10:24 pm
Hi!

Yes - it is getting stranger and stranger.

If you cast them in the const declaration as byte(64) the compiler does not complain. And gives the correct result.

Oh Lord, don't ask me questions! (© Graham Parker)

Winni
Title: Re: How to force the not operator to return a byte
Post by: MarkMLl on May 14, 2021, 11:18:31 pm
I've PMed PascalDragon and asked him to drop in.

MarkMLl
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 15, 2021, 12:19:17 am
As I understand it, you cannot use typed constants in expression in a constant declaration, because they in fact are some kind of variables (are placed in memory and initialized), while ordinary constants are analog of #define in C. This is quote from https://www.freepascal.org/docs-html/current/ref/refse9.html#x21-200002.1 :
Quote
When a previously declared ordinary constant is used in the code, the compiler will insert the actual value of the constant instead of the constant name.
Even this code
Code: Pascal  [Select][+][-]
  1. const
  2.   a : byte = 128;
  3.   c = a;
gives Illegal expression.
As for
Code: Pascal  [Select][+][-]
  1. const
  2.     a = byte(128);

this is still ordinary constant.
Title: Re: How to force the not operator to return a byte
Post by: winni on May 15, 2021, 12:36:42 am
As I understand it, you cannot use typed constants in expression in a constant declaration, because they in fact are some kind of variables (are placed in memory and initialized) ....

Hi!

Yes , you are right. We are still fighting with the idiotic Borland decision about typed constants from the last millenium.
And all that nonsense due to Delphi compatibility.

Winni
Title: Re: How to force the not operator to return a byte
Post by: speter on May 15, 2021, 03:40:32 am
interestingly, even the following gives a warning:
Code: Pascal  [Select][+][-]
  1. const
  2.   a = word(128);
  3.   b = word(64);
  4.   c = word(a or b);
  5.   d = byte(not c);   // Warning: range check error ... (-193)
  6.   e = word(not c);
  7.   f = byte(e);       // Warning: range check error ... (65343)
  8.   g = byte(lo(e));
  9.  
unit1.pas(56,8) Warning: range check error while evaluating constants (-193 must be between 0 and 255)
^^^^(56 = line 5 in the code above)
unit1.pas(58,7) Warning: range check error while evaluating constants (65343 must be between 0 and 255)
^^^^(58 = line 7 in the code above)

The code produces the following output (Win 10, 64bit)
Code: Text  [Select][+][-]
  1. a = 128
  2. b = 64
  3. c = 192
  4. d = 63
  5. e = 65343
  6. f = 63
  7. g = 63

cheers
S.
Title: Re: How to force the not operator to return a byte
Post by: speter on May 15, 2021, 03:59:49 am
To answer the original question (in the subject line) :)
Code: Pascal  [Select][+][-]
  1. const
  2.   a = 128;
  3.   b = 64;
  4.   c = byte(lo(not (a or b)));

The code above gives the correct answer and has no warnings. :)

cheers
S.

PS: interestingly, the following code gives a compiler error:
Code: Pascal  [Select][+][-]
  1. const
  2.   a = 128;
  3.   b = 64;
  4.   c : byte = lo(not (a or b));
Error: range check error while evaluating constants (4294967103 must be between 0 and 255)
Title: Re: How to force the not operator to return a byte
Post by: engkin on May 15, 2021, 06:10:20 am
It is NOT a problem

SizeOf(NOT SomeValue) equals SizeOf(PtrInt)
that is 4 or 8 bytes

If the result is negative, it will NOT fit in any thing less than PtrInt. Or so the compiler thinks.

We have TWO solutions, NOT one:
1-Do NOT use NOT:
Code: Pascal  [Select][+][-]
  1. c=$FF xor (a or b);

OR

2-Do use NOT:
Code: Pascal  [Select][+][-]
  1. c=not (a or b) and $FF

1st Edit:
The first solution assumes both a and b are bytes.
The second solution does NOT care.

2nd Edit:
It's a feature If recent versions of Delphi.give similar warning?
Title: Re: How to force the not operator to return a byte
Post by: Roland57 on May 15, 2021, 07:49:24 am
Thank you all for the interesting discussion.

@speter

Sorry but, unless I am doing something wrong, your proposition doesn't seem to solve the problem: I still have a warning. (FPC 3.2.0, Linux 64.)

@engkin

Thank you. Both solutions work indeed.
Title: Re: How to force the not operator to return a byte
Post by: MarkMLl on May 15, 2021, 09:12:43 am
As I understand it, you cannot use typed constants in expression in a constant declaration, because they in fact are some kind of variables (are placed in memory and initialized), while ordinary constants are analog of #define in C. This is quote from https://www.freepascal.org/docs-html/current/ref/refse9.html#x21-200002.1 :

Although I'd tried using the directive which should have disabled that.

MarkMLl
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 15, 2021, 09:51:42 am
As I understand it, you cannot use typed constants in expression in a constant declaration, because they in fact are some kind of variables (are placed in memory and initialized), while ordinary constants are analog of #define in C. This is quote from https://www.freepascal.org/docs-html/current/ref/refse9.html#x21-200002.1 :

Although I'd tried using the directive which should have disabled that.

MarkMLl
This directive does not make them ordinary constants, it only tells compiler to place them in read-only memory (if architecture and system allow this).
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 15, 2021, 10:20:00 am
PS: interestingly, the following code gives a compiler error:
Code: Pascal  [Select][+][-]
  1. const
  2.   a = 128;
  3.   b = 64;
  4.   c : byte = lo(not (a or b));
Error: range check error while evaluating constants (4294967103 must be between 0 and 255)

This code gives error when Range check (-Cr) option is on, otherwise it gives warning.
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 15, 2021, 10:30:31 am
The first solution assumes both a and b are bytes.

If a and b are ordinary constants, they cannot be bytes. They do not reside in memory. They are evaluated to NUMBERS with some rules by compiler (for C we would say by preprocessor) before real compilation.
For ordinary constants we can speak only about range.
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 15, 2021, 10:33:36 am
In retrospect, I rather wish I'd not got involved in this :-)
Me too. This discussion practically scared the hell out of me

I'd hoped I can use fpc (my old beloved pascal) for low-level programming. Now I have my second thought about it.

I often use bitwise operations, e.g.
Code: [Select]
reg |= BITNO;
reg &= ~BITNO;
to set/clear a bit in a IO register which the C compiler usually translates the latter to a single assembly instruction.

Not sure it will work here.

Perhaps it is better to stick with the C-code for embedded purposes.
Title: Re: How to force the not operator to return a byte
Post by: engkin on May 15, 2021, 07:53:04 pm
The first solution assumes both a and b are bytes.

If a and b are ordinary constants, they cannot be bytes. They do not reside in memory. They are evaluated to NUMBERS with some rules by compiler (for C we would say by preprocessor) before real compilation.
For ordinary constants we can speak only about range.

Yes, thank you. That's exactly what I meant. a and b should be within the range of what fits in a byte: 0..255 because "$FF xor" was used as a replacement for binary NOT. I should have made this clear but somehow I assumed it was obvious.
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 15, 2021, 10:19:19 pm
SizeOf(NOT SomeValue) equals SizeOf(PtrInt)
that is 4 or 8 bytes

Not correct! Tested with FPC 3.2
Code: Pascal  [Select][+][-]
  1. var
  2.   B: Byte;
  3.   I: Integer;
  4. begin
  5.   I := SizeOf(not B); // = 1!

And why
Code: Pascal  [Select][+][-]
  1. $FF xor B
should be treated differently than
Code: Pascal  [Select][+][-]
  1. not B
?
Title: Re: How to force the not operator to return a byte
Post by: engkin on May 15, 2021, 11:20:40 pm
SizeOf(NOT SomeValue) equals SizeOf(PtrInt)
that is 4 or 8 bytes

Not correct! Tested with FPC 3.2
Code: Pascal  [Select][+][-]
  1. var
  2.   B: Byte;
  3.   I: Integer;
  4. begin
  5.   I := SizeOf(not B); // = 1!

How about you do the correct test!
Code: Pascal  [Select][+][-]
  1. const
  2.   b=1;
  3.  
  4. begin
  5.   WriteLn(SizeOf(b));
  6.   WriteLn(SizeOf(NOT b));
  7. //OR
  8.   WriteLn(SizeOf(1));
  9.   WriteLn(SizeOf(NOT 1));

Constants, remember? Ordinal constants.

And why
Code: Pascal  [Select][+][-]
  1. $FF xor B
should be treated differently than
Code: Pascal  [Select][+][-]
  1. not B
?

Hopefully you see the reason now.
Title: Re: How to force the not operator to return a byte
Post by: winni on May 15, 2021, 11:35:21 pm
RTFM!

Siezof returns the size of variables. Simple as well as records.

And if do a sizeof(SomePointer) it return the size of the pointer.

That's why it is called sizeof.

Winni
Title: Re: How to force the not operator to return a byte
Post by: engkin on May 15, 2021, 11:55:57 pm
Great information, Winni!!

Are you suggesting a bug in SizeOf or its documentation?
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 16, 2021, 12:32:28 am
*snip*

How about you do the correct test!
Code: Pascal  [Select][+][-]
  1. const
  2.   b=1;
  3.  
  4. begin
  5.   WriteLn(SizeOf(b));
  6.   WriteLn(SizeOf(NOT b));
  7. //OR
  8.   WriteLn(SizeOf(1));
  9.   WriteLn(SizeOf(NOT 1));

Constants, remember? Ordinal constants.

I see. But you wrote:
Code: Pascal  [Select][+][-]
  1. SizeOf(NOT SomeValue) equals SizeOf(PtrInt)

 It's a sloppy writing.

And why
Code: Pascal  [Select][+][-]
  1. $FF xor B
should be treated differently than
Code: Pascal  [Select][+][-]
  1. not B
?

Hopefully you see the reason now.

Actually, no. May be you're hopeful that I can differentiate between (128 or 64) and $FF but I can't. Both:
Code: [Select]
not (128 or 64) and
Code: [Select]
$FF xor (128 or 64) are non-terminal <expr> on terminals $FF, 128, 64 (all fit in a byte, i.e. 0..2^8-1) and I can't see the reason the former will be widened to PtrInt and the latter -not.
Nowhere I can see a type hint to the compiler as it would be if they're declared as variables (e.g. V: Type).
Why the widening rules for not and xor would differ?


 
Title: Re: How to force the not operator to return a byte
Post by: winni on May 16, 2021, 12:34:01 am
Hi !

I have read the sizeof documentation of UCSD Pascal 40 yers ago.Since then has not much changed.

Winni

Title: Re: How to force the not operator to return a byte
Post by: winni on May 16, 2021, 01:02:04 am
Hi!

Perhaps one usefull tip:

If you use NOT without any type casting, the result is in the native size of your machine:

On 32Bit machines it is 4 bytes
On 64Bit machines it is 8 bytes

It does not matter if the input is a byte, a word or an integer.

Winni

Title: Re: How to force the not operator to return a byte
Post by: engkin on May 16, 2021, 01:10:58 am
*snip*

How about you do the correct test!
Code: Pascal  [Select][+][-]
  1. const
  2.   b=1;
  3.  
  4. begin
  5.   WriteLn(SizeOf(b));
  6.   WriteLn(SizeOf(NOT b));
  7. //OR
  8.   WriteLn(SizeOf(1));
  9.   WriteLn(SizeOf(NOT 1));

Constants, remember? Ordinal constants.

I see.

I thought that meant we are done!!

But you wrote:
Code: Pascal  [Select][+][-]
  1. SizeOf(NOT SomeValue) equals SizeOf(PtrInt)

 It's a sloppy writing.

Why do think it is sloppy? How do you prefer I write it?


And why
Code: Pascal  [Select][+][-]
  1. $FF xor B
should be treated differently than
Code: Pascal  [Select][+][-]
  1. not B
?

Hopefully you see the reason now.

Actually, no. May be you're hopeful that I can differentiate between (128 or 64) and $FF but I can't. Both:
Code: [Select]
not (128 or 64) and
Code: [Select]
$FF xor (128 or 64) are non-terminal <expr> on terminals $FF, 128, 64 (all fit in a byte, i.e. 0..2^8-1) and I can't see the reason the former will be widened to PtrInt and the latter -not.
Nowhere I can see a type hint to the compiler as it would be if they're declared as variables (e.g. V: Type).
Why the widening rules for not and xor would differ?

I don't have a Delphi. Do you have [access to] a recent version of Delphi?
If Delphi widens the result of NOT, FPC is going to follow for compatibility. Otherwise it is a bug.
Title: Re: How to force the not operator to return a byte
Post by: engkin on May 16, 2021, 01:13:06 am
Hi!

Perhaps one usefull tip:

If you use NOT without any type casting, the result is in the native size of your machine:

On 32Bit machines it is 4 bytes
On 64Bit machines it is 8 bytes

It does not matter if the input is a byte, a word or an integer.

Winni

Yes, Winni, that is correct. Is it documented? How about Delphi?
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 16, 2021, 01:20:40 am
Hi !

I have read the sizeof documentation of UCSD Pascal 40 yers ago.Since then has not much changed.

Winni
+1 for mentioning UCSD Pascal.

I doubt it has SizeOf, it is a C/C++ operator and should return the actual storage size of a variable or a type. As long it is used over a constant, which should be substituted as a literal, (@engkin) it can be considered as a bug.

IMHO,
Quote
If Delphi widens the result of NOT, FPC is going to follow for compatibility. Otherwise it is a bug.
is not an excuse.
Title: Re: How to force the not operator to return a byte
Post by: engkin on May 16, 2021, 01:31:29 am
(@engkin) it can be considered as a bug.

The OP made it clear that it changed after FPC 3.0.4.
Mark PMed PascalDragon, but we did not see his response.
Without comparing it with Delphi I cannot be sure if it is a bug or a feature.
Since you are that sure, maybe you can file a bug report.
Title: Re: How to force the not operator to return a byte
Post by: winni on May 16, 2021, 01:33:28 am
Hi!

As I said:

If you repair a Delphi bug in Lazarus, it is considered to be a bug, because it is not Delphi compatible.

That's the way to bring people in the madhouse.

Winni
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 16, 2021, 01:47:45 am
*snip*
Since you are that sure, maybe you can file a bug report.
I'd rather not use sizeof that way.
What bothers me more is the different interpretations of the otherwise identical bitwise not and xor
Title: Re: How to force the not operator to return a byte
Post by: engkin on May 16, 2021, 02:36:22 am
*snip*
Since you are that sure, maybe you can file a bug report.
I'd rather not use sizeof that way.
What bothers me more is the different interpretations of the otherwise identical bitwise not and xor

Just to be clear, when I mentioned the bug report I was talking about NOT.
Title: Re: How to force the not operator to return a byte
Post by: BobDog on May 16, 2021, 11:20:44 am

Getting all tied up here, that's for sure.
Code: Pascal  [Select][+][-]
  1.  
  2. {$MACRO ON}
  3.  {$define c:= knot(a or b) }
  4.  
  5.  const
  6.  a=128;
  7.  b=64;
  8.  
  9.   function knot(i:integer):byte;
  10.   begin
  11.   exit(not i);
  12.   end;
  13.  
  14. begin
  15. writeln(c);
  16. writeln;
  17. readln;
  18. end.
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 16, 2021, 12:28:03 pm
What bothers me more is the different interpretations of the otherwise identical bitwise not and xor

It seems that you do not understand the difference between byte variables and ordinary constants. Then consider them as integers.  :D
And maybe the output of this code will help you.
Code: Pascal  [Select][+][-]
  1. const
  2.   a = 128;
  3.   b = 64;
  4.   c = not (a or b);
  5.   d = $FF xor (a or b);
  6.  
  7. var
  8.   ba : byte = 128;
  9.   bb : byte = 64;
  10.   bc, bd : byte;
  11.  
  12.   ia : integer = 128;
  13.   ib : integer = 64;
  14.   ic, id : integer;
  15.  
  16. begin
  17.   writeln('constants');
  18.   writeln(c);
  19.   writeln(d);
  20.   writeln;
  21.  
  22.   bc := not (ba or bb);
  23.   bd := $FF xor (ba or bb);
  24.   writeln('bytes');
  25.   writeln(bc);
  26.   writeln(bd);
  27.   writeln;
  28.  
  29.   writeln('integers');
  30.   ic := not (ia or ib);
  31.   id := $FF xor (ia or ib);
  32.   writeln(ic);
  33.   writeln(id);
  34.   readln;
  35. end.  
Title: Re: How to force the not operator to return a byte
Post by: molly on May 16, 2021, 12:51:05 pm
Not(constant) does something different then is assumed xor does not suffer from this negation 'error'.

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. {$MODE OBJFPC}
  4.  
  5. (*
  6. https://freepascal.org/docs-html/ref/refsu4.html#x26-250003.1.1
  7.  
  8. With the exception of floating point value types, all base types
  9. are ordinal types.
  10.  
  11. A list of predefined integer types is presented in table (3.1).
  12.  
  13. Remark: The compiler decides on the type of an integer constant
  14. based on the value: An integer constant gets the smallest possible
  15. signed type. The first match in table (3.3) is used.
  16.  
  17. That means constants in the range -128..127 are mapped to shortint,
  18. constants in range 128..255 are mapped to byte, etc.
  19. Constants in the range 2147483647..high(cardinal) are parsed as
  20. cardinals, and all decimal constants which do not fit either of
  21. the above ranges are parsed as 64-bit integer constants.
  22.  
  23. As a pascal compiler, Free Pascal does automatic type conversion and
  24. upgrading in expressions where different kinds of integer types are
  25. used:
  26. 1 Every platform has a “native” integer size, depending on whether
  27.   the platform is 8-bit, 16-bit, 32-bit or 64-bit. E. g. on AVR this
  28.   is 8-bit.
  29. 2 Every integer smaller than the “native” size is promoted to a
  30.   signed version of the “native” size. Integers equal to the “native”
  31.   size keep their signedness.
  32. 3 The result of binary arithmetic operators (+, -, *, etc.) is
  33.   determined in the following way:
  34.   a If at least one of the operands is larger than the native integer
  35.     size, the result is chosen to be the smallest type that encompasses
  36.     the ranges of the types of both operands. This means that mixing an
  37.     unsigned with a smaller or equal in size signed will produce a
  38.     signed type that is larger than both of them.
  39.   b If both operands have the same signedness, the result is the same
  40.     type as them. The only exception is subtracting (-): in the case of
  41.     unsigned - unsigned subtracting produces a signed result in FPC
  42.     (as in Delphi, but not in TP7).
  43.   c Mixing signed and unsigned operands of the “native” int size
  44.     produces a larger signed result. This means that mixing longint and
  45.     longword on 32-bit platforms will produce an int64. Similarly,
  46.     mixing byte and shortint on 8-bit platforms (AVR) will produce
  47.     a smallint.
  48. *)
  49.  
  50. begin
  51.   WriteLn(64);
  52.   WriteLn(SizeOf(64));
  53.   WriteLn(128);
  54.   WriteLn(SizeOf(128));
  55.   WriteLn(128 or 64);
  56.   WriteLn(SizeOf(128 or 64));
  57.   WriteLn(not(128 or 64));
  58.   WriteLn(SizeOf(not(128 or 64)));
  59. end.
  60.  
  61. (*
  62.   64
  63.   1
  64.   128
  65.   1
  66.   192
  67.   1
  68.   -193
  69.   8
  70. *)
  71.  
  72.  

It's written in the documentation. It requires to read those line that apply for this situation  ;)
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 16, 2021, 12:56:40 pm
@BobDog
I think for the original OP question it is:
Code: Pascal  [Select][+][-]
  1. const
  2.   a = 128;
  3.   b =  64;
  4.   c = not byte(a or b);

I must correct myself in my earlier post - in the latter versions of C/C++ sizeof is defined also on expressions as 'size of the static type of the expression'. Assuming our SizeOf() is working in a similar way, perhaps  the lack of a type hint makes him to return SizeOf(not 1) = SizeOf(PtrInt).

BTW, does anyone know where a decent documentation for FPC SizeOf() can be found?

@tetrastes
Thank you for your example! It shows me mostly the negative numbers two's complement representation.
I've taught a time ago, that constants are lexical substitutions, not integers. I doubt the things have changed since.
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 16, 2021, 01:14:57 pm
I've taught a time ago, that constants are lexical substitutions, not integers. I doubt the things have changed since.

I see you did not notice smiley at the end of that line...
To be serious, if you understand this, then I don't understand what "different interpretations" bother you?
Title: Re: How to force the not operator to return a byte
Post by: WooBean on May 16, 2021, 01:51:26 pm
BTW, does anyone know where a decent documentation for FPC SizeOf() can be found?
 

See here:  https://www.freepascal.org/docs-html/rtl/system/sizeof.html

In fact sizeof(x) can accept an expression in the place of x variable or type so sizeof(1) can give 1 and sizeof(pi/2+2) can give 8 (or 10 - depending on platform).


Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 16, 2021, 01:58:03 pm
I think for the original OP question it is:
Code: Pascal  [Select][+][-]
  1. const
  2.   a = 128;
  3.   b =  64;
  4.   c = not byte(a or b);

This code sets c to -193, this is not a byte (to be correct, not in range 0...255), what OP wants.
Moreover, casting (a or b) to byte is useless here: 128 or 64 = 192, byte(192) = 192.
You've taught a time ago, that constants are lexical substitutions...
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 16, 2021, 02:24:19 pm
Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. {$MODE OBJFPC}
  4.  
  5. (*
  6. https://freepascal.org/docs-html/ref/refsu4.html#x26-250003.1.1
  7. ...
  8.  
  9. Remark: The compiler decides on the type of an integer constant
  10. based on the value: An integer constant gets the smallest possible
  11. signed type.
  12. ...
  13. constants in range 128..255 are mapped to byte, etc.
  14. ...
  15.  

These two statements contradict each other, am I wrong?
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 16, 2021, 02:44:06 pm
This code sets c to -193, this is not a byte (to be correct, not in range 0...255), what OP wants.
Moreover, casting (a or b) to byte is useless here: 128 or 64 = 192, byte(192) = 192.
You've taught a time ago, that constants are lexical substitutions...

Quite not useless, since doesn't give a range check warning as with: c = byte(not (a or b));
I was taught well enough ;)
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 16, 2021, 02:57:17 pm
This code sets c to -193, this is not a byte (to be correct, not in range 0...255), what OP wants.
Moreover, casting (a or b) to byte is useless here: 128 or 64 = 192, byte(192) = 192.
You've taught a time ago, that constants are lexical substitutions...

Quite not useless, since doesn't give a range check warning as with: c = byte(not (a or b));
I was taught well enough ;)

Once more:
c = not byte(a or b) = not byte(128 or 64) = not byte(192) = not 192 = -193
is absolutely the same as
c = not (a or b) = not (128 or 64) = not 192 = -193
which also gives no warning.

BUT this is NOT what OP wants, because
c = byte(not (a or b)) = ... = 63
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 16, 2021, 03:34:06 pm
Once more:
c = not byte(a or b) = not byte(128 or 64) = not byte(192) = not 192 = -193
is absolutely the same as
c = not (a or b) = not (128 or 64) = not 192 = -193
which also gives no warning.

c = byte(not(a or b)) Gives the warning. (FPC 3.2)

c = not byte(a or b) Does not.

Instead of repeating, you should try to solve it with types, not numbers.

Title: Re: How to force the not operator to return a byte
Post by: engkin on May 16, 2021, 03:54:25 pm
ivanov, yes no warning, great. But now it's 4 bytes.
Title: Re: How to force the not operator to return a byte
Post by: BobDog on May 16, 2021, 03:57:17 pm
@BobDog
I think for the original OP question it is:
Code: Pascal  [Select][+][-]
  1. const
  2.   a = 128;
  3.   b =  64;
  4.   c = not byte(a or b);

I must correct myself in my earlier post - in the latter versions of C/C++ sizeof is defined also on expressions as 'size of the static type of the expression'. Assuming our SizeOf() is working in a similar way, perhaps  the lack of a type hint makes him to return SizeOf(not 1) = SizeOf(PtrInt).

BTW, does anyone know where a decent documentation for FPC SizeOf() can be found?

@tetrastes
Thank you for your example! It shows me mostly the negative numbers two's complement representation.
I've taught a time ago, that constants are lexical substitutions, not integers. I doubt the things have changed since.

The OS had originally
Code: Pascal  [Select][+][-]
  1. const
  2.   a = 128;
  3.   b =  64;
  4.   c = byte(not(a or b));
  5.  
  6. begin
  7. end.
My own snippet gives a,b as const.
c is also const (via a define).
The question was
"how to force the not operator to return a byte"
So, via a function, I have forced NOT to (eventually) return a byte via the function return.
I get no warnings with this method, although I realize that a macro is probably not really wanted.
But 63 I believe was the answer sought, so at least it produces that answer.

Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 16, 2021, 03:58:11 pm
Once more:
c = not byte(a or b) = not byte(128 or 64) = not byte(192) = not 192 = -193
is absolutely the same as
c = not (a or b) = not (128 or 64) = not 192 = -193
which also gives no warning.

c = byte(not(a or b)) Gives the warning. (FPC 3.2)

c = not byte(a or b) Does not.

Instead of repeating, you should try to solve it with types, not numbers.

c = not (a or b)   Does not. And what?

What types are you talking about for ordinary constants? Show how " to solve it with types", I don't afraid to say that I do not know that.

And why you ignore the main:
Quote
BUT this is NOT what OP wants, because
c = byte(not (a or b)) = ... = 63
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 16, 2021, 04:59:32 pm
ivanov, yes no warning, great. But now it's 4 bytes.
Oops, sorry!
Just one more typecast: c = byte( not byte(a or b) );

@BobDog
Your suggestion does the job. I've just focused on the consts, sizeof.

@tetrastes
The NOT just don't have a clue for the type of its operand and sign-extends making the value negative. Just give him what he needs, typecast, that's it.
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 16, 2021, 05:26:55 pm
@tetrastes
The NOT just don't have a clue for the type of its operand and sign-extends making the value negative. Just give him what he needs, typecast, that's it.
Yes, typecast, and
Quote
Just one more typecast: c = byte( not byte(a or b) );
gives the same warning and the same binary as
c = byte( not (a or b) );
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 16, 2021, 05:57:44 pm
@tetrastes
The NOT just don't have a clue for the type of its operand and sign-extends making the value negative. Just give him what he needs, typecast, that's it.
Yes, typecast, and
Quote
Just one more typecast: c = byte( not byte(a or b) );
gives the same warning and the same binary as
c = byte( not (a or b) );

I shall admit the last one was not correct either  :( That not operator turned out to be a tough dude.
It seems the only solution left (in the const section) is to perform some other bitwise op, like c=($FF xor (a or b)); or c = byte( not byte(a or b) and 255);

And perhaps I should eat up my diploma  :-[
Title: Re: How to force the not operator to return a byte
Post by: molly on May 16, 2021, 06:02:46 pm
Code: [Select]
Remark: The compiler decides on the type of an integer constant
based on the value: An integer constant gets the smallest possible
signed type.
...
constants in range 128..255 are mapped to byte, etc.
...

These two statements contradict each other, am I wrong?
I fail to see how these two statements could contradict. If you still think the same after reading this post then please feel free to elaborate to make me better understand.

Quote
That means constants in the range -128..127 are mapped to shortint,
constants in range 128..255 are mapped to byte, etc.

64  = shortint
128 = byte
192 = byte

The results from the posted program confirms that the resulted answers are 1 byte in size, except when the not operator comes into play.

Take the following program that also shows the bit representation of the resulted values
Code: Pascal  [Select][+][-]
  1. begin
  2.   WriteLn;
  3.   WriteLn(64);
  4.   WriteLn(SizeOf(64));
  5.   WriteLn(BinStr(64, SizeOf(64) * 8));
  6.  
  7.   WriteLn;
  8.   WriteLn(128);
  9.   WriteLn(SizeOf(128));
  10.   WriteLn(BinStr(128, SizeOf(128) * 8));
  11.  
  12.   WriteLn;
  13.   WriteLn(128 or 64);
  14.   WriteLn(SizeOf(128 or 64));
  15.   WriteLn(BinStr(128 or 64, SizeOf(128 or 64) * 8));
  16.  
  17.   WriteLn;
  18.   WriteLn(not(128 or 64));
  19.   WriteLn(SizeOf(not(128 or 64)));
  20.   WriteLn(BinStr(not(128 or 64), SizeOf(not(128 or 64)) * 8));
  21. end.
  22.  

which shows:
Code: [Select]
64
1
01000000

128
1
10000000

192
1
11000000

-193
8
1111111111111111111111111111111111111111111111111111111100111111

Now, I do not claim to know/understand how this is actually implemented in the compiler (haven't looked) but if I would have to take a guess then I assume (and that assumption might very well be wrong) that when the actual negation takes place that the negative flag (of the cpu) is set and that should be reflected in the result.
Because the highest bit is already set in byte value 192 (sign bit) the result is or needs to be expanded.

The same documentation that was quoted states that in that case result does not fit in the two explained ranges and that in such case it is expanded to a 64 integer.

That also seems to be confirmed by the resulted output.

fwiw: one could also opt for implementing a self written custom bye/word/dword type that is more in line with what is expected (such as how an assembler/cpu does things, and i assume OP expected the not operator to work). You could then also use your own custom operators for such a custom type and implement these operators to act/behave any which way you see fit. Even though the compiler does warn you explicitly when things are not going according to plan when using casting, but in that case simply ignoring the warnings might result in unexpected results/behaviour on the long run.

edit: typo's/rewording
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 16, 2021, 06:10:57 pm
*snip*
What types are you talking about for ordinary constants? Show how " to solve it with types", I don't afraid to say that I do not know that.
My point was that, the Sizeof() for example when used on expression, must evaluate the type of the expression, not the expression itself. Then substituting with the terminals (e.g. 128 for a, 64 for b) into the expression (byte(not (a or b)), and given the rules for expansion, we should be able to determine at which step the sign-extension takes place and to put a proper typecast to prevent it. But it turns out it was just a speculation.   

@molly
+1 for your detailed explanation
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 16, 2021, 06:26:13 pm
Code: [Select]
Remark: The compiler decides on the type of an integer constant
based on the value: An integer constant gets the smallest possible
signed type.
...
constants in range 128..255 are mapped to byte, etc.
...

These two statements contradict each other, am I wrong?
I fail to see how these two statements could contradict. If you still think the same after reading this post then please feel free to elaborate to make me better understand.
An integer constant gets the smallest possible SIGNED type.
...
constants in range 128..255 are mapped to BYTE

Byte is unsigned type, so according to first statement constants in range 128..255 must be mapped to SmallInt.
But English is not my native language, and maybe I don't undestand something... 
Title: Re: How to force the not operator to return a byte
Post by: molly on May 16, 2021, 07:08:30 pm
Ah, thank you for the elaboration tetrates.

Now I am able to understand why you might think that.

If you look at the original text: https://freepascal.org/docs-html/ref/refsu4.html#x26-250003.1.1

The statement at the remark-part is a generic statement on how the compiler works. Immediately after that statement the original documentation elaborates on how that is done by the compiler by telling:

Quote
The first match in table (3.3) is used.
By using the table you are able to determine the order of precedence.

fwiw: I left out the actual table in my code because I have beter things to do other than copying a html-table into source-code  :D

First the compiler tries to match shortint, then byte, then smallint, etc, and as shown in the table.

The number/value 64 first match is that of a shortint.
the number/value 128 does not fit in a shortint and the next candidate in the table is a byte.
the same applies the number/value 192.

The resulting answer/value turning into a 64 bit integer is the exception, which is also explained by the documentation (note that the 64-bit is mentioned in the documentation, but that might differ because the documentation can be different for other platforms and therefor not always return a 64-bit integer. e.g. that could also be a 32-bit integer on 32 bit cpu, or perhaps an even smaller integer depending on the platform).

Does the above explanation compute better for you ?

Quote
y.ivanov wrote:
@molly
+1 for your detailed explanation
Thank you for the +1 but I can't really take the credit for that as others have (more or less) stated the same.

The only thing I did is make it a bit more easier to understand by creating an example that is as simple as possible to understand and that matches the documentation.

In case the example and explanation was able to help the reader better understand of what is actually happening then I'm glad I was able to help out (a little).

Practise shows that it is far more difficult to be able to disprove what is written in the documentation , and then nag about that :P
Title: Re: How to force the not operator to return a byte
Post by: tetrastes on May 16, 2021, 07:23:34 pm
@molly
Thank you for explanations, I understand all. But I still think that the first statement must be "An integer constant gets the smallest possible INTEGER type".
Title: Re: How to force the not operator to return a byte
Post by: lucamar on May 16, 2021, 07:54:38 pm
Thank you for explanations, I understand all. But I still think that the first statement must be "An integer constant gets the smallest possible INTEGER type".

Context is everything here ;)

The original wording is because it's a quotation from the documentation and it refers to the table of integer types, so "smallest possible signed type" in this case has to be taken to mean "smallest possible signed type from those in the table above [of predefined integer types]".
Title: Re: How to force the not operator to return a byte
Post by: alpine on May 16, 2021, 08:11:21 pm
Here are the snippets from the compiler source:
Code: Pascal  [Select][+][-]
  1. // from pexpr.pas
  2. ...
  3.             _INTCONST :
  4.                begin
  5.                  {Try first wether the value fits in an int64.}
  6.                  val(pattern,ic,code);
  7.                  if code=0 then
  8.                    begin
  9.                       consume(_INTCONST);
  10.                       int_to_type(ic,hdef);
  11.                       p1:=cordconstnode.create(ic,hdef,true);
  12.                    end
  13.                  else
  14.                    begin
  15.                      { try qword next }
  16.                       ...
  17.                  if code<>0 then
  18.                    begin
  19.                      { finally float }
  20.                       ...
  21.  
  22. // from defutil.pas
  23.   ...
  24.     procedure int_to_type(const v:TConstExprInt;var def:tdef);
  25.       begin
  26.         range_to_type(v,v,def);
  27.       end;
  28. ...
  29.     procedure range_to_type(const l,h:TConstExprInt;var def:tdef);
  30.       begin
  31.         { prefer signed over unsigned }
  32.         if (l>=int64(-128)) and (h<=127) then
  33.          def:=s8inttype
  34.         else if (l>=0) and (h<=255) then
  35.          def:=u8inttype
  36.         else if (l>=int64(-32768)) and (h<=32767) then
  37.          def:=s16inttype
  38.         else if (l>=0) and (h<=65535) then
  39.          def:=u16inttype
  40.         else if (l>=int64(low(longint))) and (h<=high(longint)) then
  41.          def:=s32inttype
  42.         else if (l>=low(cardinal)) and (h<=high(cardinal)) then
  43.          def:=u32inttype
  44.         else if (l>=low(int64)) and (h<=high(int64)) then
  45.          def:=s64inttype
  46.         else
  47.          def:=u64inttype;
  48.       end;
  49. ...

I believe the code of procedure range_to_type says it all. No more contradictions.  :D
Title: Re: How to force the not operator to return a byte
Post by: Roland57 on May 16, 2021, 09:07:51 pm
Thank you all for the very informative discussion.  :)
Title: Re: How to force the not operator to return a byte
Post by: winni on May 16, 2021, 09:17:30 pm


To be, Or Not (to be )

Hamlet, Shakespeare


Title: Re: How to force the not operator to return a byte
Post by: engkin on May 16, 2021, 10:54:13 pm
Here is the source code for NOT:
Code: Pascal  [Select][+][-]
  1. //nmat
  2. function tnotnode.simplify(forinline : boolean):tnode;
  3. ...
  4. { constant folding }
  5. if (left.nodetype=ordconstn) and
  6.   (left.resultdef.typ=orddef) then
  7.   begin
  8.     v:=tordconstnode(left).value;
  9.     def:=left.resultdef;
  10. ....
  11.     uchar,
  12.     uwidechar,
  13.     u8bit,
  14.     s8bit,
  15.     u16bit,
  16.     s16bit,
  17.     s32bit,
  18.     u32bit,
  19.     s64bit,
  20.     u64bit:
  21.       begin
  22.         { unsigned, equal or bigger than the native int size? }
  23.         if (torddef(left.resultdef).ordtype in [u64bit,u32bit,u16bit,u8bit,uchar,uwidechar]) and
  24.            (is_nativeord(left.resultdef) or is_oversizedord(left.resultdef)) then
  25.           begin
  26.             { Delphi-compatible: not dword = dword (not word = longint) }
  27.             { Extension: not qword = qword                              }
  28.             v:=qword(not qword(v));
  29.             { will be truncated by the ordconstnode for u32bit }
  30.           end
  31.         else
  32.           begin
  33.             v:=int64(not int64(v));
  34.             def:=get_common_intdef(torddef(left.resultdef),torddef(sinttype),false);
  35.           end;
  36.       end;

So NOT is computed as:
Code: Pascal  [Select][+][-]
  1.             v:=int64(not int64(v));

"will be truncated by the ordconstnode for us32bit"
TinyPortal © 2005-2018