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*. > > 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. > > 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). > > 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. > 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. > 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 _______________________________________________ fpc-devel maillist - [email protected] http://lists.freepascal.org/mailman/listinfo/fpc-devel
