CBFalconer wrote:
Frank Heckenbach wrote:
Yes, with `pow' standing for integer powers as defined in EP (if you don't like that, you can insert the usual recursive definition of powers, of course), I think we can define:
a shl b := a * 2 pow b
Your definition is clearer if you use some parentheses.
asl(a, b) := a * (2 pow b)
and I strongly favor making these syntactical extensions functions (so they can be easily replaced in purely standard systems)
Sorry, but this discussion is not really about syntax. We want to be compatible with other compilers where that's easily possible, and several other compilers use such operators. This is just about the semantics which, in other compilers, after often only defined poorly (or accidentally, or for special circumstances).
and naming them asl, asr when they consider the sign. That allows clear distinction from lsl, lsr which insert 0 bits at one end or the other, and can be defined to never create an overflow by using modular arithmetic as in C unsigned.
As I wrote, this makes the operations dependent on the type size. That's why C needs to distinguish between a "short" and a "long" number 1 (and various other sizes), even for constants (`0L' etc.). I definitely don't want such semantics in GPC and prefer value-based identity (in accordance with the standards as far as arithmetics are concerned).
That's my main grief with C's "modular arithmetics"(*). While something like 3 * MaxInt would be an error in Pascal (though GPC doesn't currently detect it), the equivalent expression (on usual types) in C is *defined* to be equal to MaxInt - 2.
(*) BTW, it's not really modular arithmetics, as e.g. `/' is defined quite differently (e.g., modulo 16: 3 / 7 = 5, while in C arithmetics 3 / 7 = 0). Modular arithmetics is often claimed by C supporters who want to argue that C has much resemblance to mathematics, but it doesn't really apply.
One potential problem with shl is that it can easily produce overflows. Currently it's not a practical problem, as GPC doesn't do overflow checks, but when it does, we'll have to consider this case. We could define `shl' to "ignore overflows", but this would again make the semantics type-size-dependent. Of course, a
This is why the arithmetic and logical shift operations should be firmly separated. The logicals will be defined in terms of modulo arithmetic, just as C does.
Overflow can happen with signed and unsigned types just as well. I fail to see your point here.
Rotates are problematic since they indeed depend on the type size. I see no way to define them independently. I've had a discussion with Mirsad Todorovad about these, and we came to the conclusion that it's probably more trouble than it helps. E.g., if a is a constant and we use the term `a ror 4', suddenly the type of the constant becomes very important (not just for whether there's an overflow, but it would change the result completely) which is contrary to Pascal's rules.
Again, define them as functions, and let the function parameters include the size in terms of binary bit count:
FUNCTION ror(in : T, places, bits : int) : T;
This would be possible, but could easiy lead to less efficient code when places or bits is variable. I'm writing "or" because I'm not really sure which means what -- to me "places" and "bits" means basically the same in this context. Which one is the rotation count and which one corresponds to the "type size"?
Frank