lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

On 18/01/2010 13:13, Mike Pall wrote:
> If you have directional shifts, then special casing negative
> shifts is superfluous. Nobody has asked for that feature and not a
> single use case has been presented for it.

Converting pixel formats.

We can describe a conversion from one RGB pixel format as a sequence of
masks and rotations, oring the results together. For example RGB888 to

{ 0x00f80000, -8,
  0x0000fc00, -5,
  0x000000f8, -3 }

Converting RGB565 to RGB888:

{ 0xf800, +8,
  0x07e0, +5,
  0x001f, +3 }

Converting RGB565 to BGR565:

{ 0xf800, -11,
  0x07e0, 0,
  0x001f, +11 }

(Done off the top of my head, probably contains stupid mistakes. And
yes, I know I'm not scaling 5-bit to 8-bit entirely correctly.)

This is stuff I've actually done in real life. Being able to shift by
positive and negative amounts (and by zero!) and get sensible results is
actually useful.

It also follows Principle of Least Surprise: conceptually, a right shift
can be thought of as:

  function rshift(value, shift) return int(value * pow(2, shift)) end

...then I would expect shifting by 0 or a negative number to do the
obvious thing, i.e. do nother or shift backwards.

> I repeat my arguments for masking the shift counts:
> - It enforces defined behavior.
> - It's based on actual needs of users.
> - It simplifies a majority of actual use cases.
> - It works consistently for *all* shift or rotate instructions.
> - It's consistent with the input conversions for other bit op
>   arguments that respect the requirements of modular arithmetics.
> - Performance is better that way, too.

Again, I don't agree.

Principle Of Least Surprise tells me that a shift by multiple bits is
equivalent to a series of shifts by one bit. This means that shifting by
out-of-range values will convert the value to 0 or -1, depending on the
direction and type of shift. For rotations, sure, then masking the
amount makes sense (since the operation is intrinsically modular
anyway). But for shifts? I don't see how anyone could possibly expect a
left shift by 33 to be equivalent to a left shift of 1.

This, too, is something I've been bitten by in real life. C's undefined
behaviour of out-of-range and zero shifts came as a horrible surprise.
I've already described the experience we had shifting by zero on the
Transputer. I did a lot of work implementing table-driven assemblers and
disassemblers, and did an awful lot of shifting and masking to construct
and decode instructions, and I ran into this kind of thing frequently.

>>> - Arithmetic right shift is not optional.
>> Not sure.
> You do not present any arguments. Actual use cases show that there
> is a need. Existing bit libraries offer this functionality for
> that reason, too.

I agree with you on this. Arithmetic right shift is a primitive
operation and I couldn't live without it.

> As we all know, Lua is used because it's a dynamic language where
> it's easy to write elegant, consistent and platform-independent
> code with. And it owes much of it's popularity to its superior
> performance. These are in fact its main selling points.
> I cannot see how it's deemed acceptable to compromise on these
> values, especially when there is a solution available that
> conserves all of these properties.

C defines things like out-of-range shifts to be undefined for
performance reasons; different processors behave oddly in different ways
to out-of-range shifts, and making them undefined behaviour means that
the compiler doesn't have to special-case them. But C is not Lua, and a
decision that suits C does not necessarily suit Lua.

I use Lua because it's an elegant, consistent, platform-independent and
fast *high-level language*. For me, the killer feature is that it's
high-level. I'm not willing to sacrifice the high-levelness and
consistency for a rather small performance boost. Consistency beats fast
any day in my book --- my time is more valuable than the computer's.

David Given