Marcel Martin wrote> Why not? I expect that the compiler evaluates constant expressions, and
> creates the best code for the resulting values.
The best code is, before all, the correct code.
So we have to find out what is *correct*.
Show quoted text 8 lines
> In the case of Inc(x, SomeConstant) the value of the named constant can
> be changed, with arbitrary positive or negative values. Would you then
> want to find all uses of "someconst" in your code, to find out where
> your code deserves a modification?
If I declare a constant as an unsigned integer, if I wrote my
code assuming it is an unsigned integer and if, suddenly,
I decide to change that, of course, I may expect some problems.
Why should one expect problems when incrementing or decrementing an value, maybe signed or unsigned?
Note: I have the feeling that you are confusing signed/unsigned
and negative/positive. When I talk of unsigned integers, I am not
talking about signed ones that may be positive. No, I am talking
about integers that can never be negative.
I do not confuse anything like that.
Show quoted text 10 lines
> IMO every calculation, that can result in illegal results in *normal*
> operation, has to be handled appropriately in the code. If no problems
> are predicted, expected, and handled, in explicit code, the compiler
> only has to care about coding errors, that result in *unexpected*
> overflows. I don't think that a calculation should produce or not
> produce an overflow, depending only on the sign of the given value.
Unexpected overflows? The overflows occur or not according to
simple rules, perfectly defined, which ones depend on the types
of the operands.
Unexpected as depending on the values, not on the types. When the ranges of the possible operands are known, it's also known whether an overflow can occur in computations with these operands.
If A is a Longword (this is an unsigned type, no instance can be
negative). So if A = 2^32-1 and if I compute A + 1, there is an
overflow because the resulting value should be 2^32 and this value
doesn't exist for the Longword type.
No doubt, when the compiler doesn't extend the range of the arguments (see below).
Show quoted text 10 lines
> From
> the mathematical viewpoint +(+1) and -(-1) is perfectly equivalent, as
> is +(-1) and -(+1).
Computationally, this is not equivalent.
+(-1) -> add eax, $ffffffff
-(+1) -> sub eax, $00000001
And at this point, even if we know the content of eax before the
operation, we cannot know if there is or not an overflow without
knowing the type of the integer contained in eax.
Since the hardware cannot know whether $ffffffff is a huge unsigned number, or a small signed number, a possibly thrown or indicated overflow from above instructions is meaningless. This is why a proper and unoptimized implementation must extend values of different signedness to the next bigger type, so that the calculation cannot produce an overflow.
When you consult Wirth and the design of Pascal and his following languages, you'll find out that unsigned data types always are subranges of bigger signed data types. This is why we cannot have an proper UInt64 type without an proper Int128 type, unless one wants to break all sane design rules.
Show quoted text 5 lines
Moreover, when programming, mathematical considerations have to
be handled with care. Mathematically, (x = -x) -> (x = 0).
Computationally, this is wrong (because the computer doesn't work
over the ring Z but over a ring Z/2^kZ). If x is a Longint and
if x = -x, either x = 0 or x = -2^31.
Bad example. In 2's complement both 0 and -2^31 have no counterpart of the opposite sign, whereas in 2-1 complement (sorry, don't know the English term) the negative values are represented by the bitwise complement of the positive values. When there exists no representation of -(-2^31), you cannot perform an comparison with that value.
Show quoted text 11 lines
Try this
x : Longint;
...
x := Longint($80000000); // x := -2^31
WriteLn(IntToStr(x));
x := -x;
WriteLn(IntToStr(x));
(And this is not a bug. This is a consequence of the 2-complement
representation of signed integers.)
It is a bug. As outlined before, the above assignment of x:=-x should raise an range check error. A comparison of x=-x will return False, in the Int64 range.
The expression Longint($80000000) is questionable because, in the strict sense, it forces the compiler to perform an illegal operation, which only happens to produce an in-range value on specific machines.
I know that unsigned values frequrently are not appropriately handled by many compilers, for *performance* reasons. I also know that many external routines use unsigned values in an inappropriate way, only because it's easier to define an "unsigned int" instead of an proper subrange, and because many languages do not support subrange types at all. I agree that we must live with such weird declarations, but there exists no need, besides performance, for handling such datatypes in an inappropriate way. When you rethink all your arguments and examples, based on an compiler that maps unsigned data types into subranges of the next higher signed type, you'll find out that all problems go away. Every "optimization", violating that rule, will cause selfmade trouble :-(
DoDi