Implemenation Indepdent Way to Move LSByte of Char to MSB of Int, etc

E

Eric Sosman

pete said:
One common form of undefined behavior
for the above mentioned 5 bit field,
is that for (u >> x), you wind up shifting by (x % 31) bits.

Haven't seen that one. I think you mean either
`x & 31' or `x % 32'.
 
D

dandelion

Shifting by zero bits is even more pointless, but that
doesn't seem to have prompted instruction-set designers to
omit the operation (unless they also omit all multi-bit
shifts; I've used machines whose only shift instructions
were single-bit shifts).

True. However, I have two slight remarks:

* Shift by zero does not exceed the architecture's bounds
* Checking for shift by zero requires an explicit check, which requires
extra silicon,
which would imply some sort of fault condition being set, which requires
even more silicon...
Limiting the maximum shift only requires truncating and operand, which
requires *less* silicon than
passing the full monty.

And that, I think, is the motivation for hardware ceilings on shift
counts.

Agreed.

<snip>

Ok. I wrote the above without reading the rest of your post, but we seem to
be of one opinion on this.
All right, how about "conjecture?" Or would you prefer
"damfoolishness?"

Well, calling it "damnfoolishness" would be inconsistent on my part, since
I fully agreed with the post in the first place. "Conjecture" does fit the
bill, but personally I would go for "hunch", "guess" or something like that.
 
L

Lawrence Kirby

dandelion wrote:
....


Shifting by zero bits is even more pointless,

It is for an instruction with a constant shift count, not for one with a
variable count. The count may legitimately be calculated as zero at
runtime. Similarly the situation with large shifts resulting in zero makes
some sense for a variable shift count but is less commonly needed than a
zero shift.

Lawrence
 
B

bd

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Eric Sosman wrote:

[...]
Maybe there's a way to calculate (UINT_MAX + 1)/(UCHAR_MAX + 1)
without risking zero in the numerator and/or denominator, but I
haven't figured one out. (Note that UCHAR_MAX == ULLONG_MAX is
permitted by the Standard.)

Since UCHAR_MAX <= UINT_MAX <= ULLONG_MAX...

#if UCHAR_MAX == ULLONG_MAX
# define UINT_UCHAR_RATIO 1
#else
# define UINT_UCHAR_RATIO \
(((unsigned long long)UINT_MAX + 1) / \
((unsigned long long)UCHAR_MAX + 1))
#endif

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)

iD8DBQFB7Bl1+hz2VlChukwRAoaVAJ0Zh2DOJwBXkeNRuyG/Jd0h9dx5cACcCD6a
ybh2nBGeJaFbYrAwuhhhMhA=
=otfo
-----END PGP SIGNATURE-----
 
E

Eric Sosman

bd said:
Eric Sosman wrote:
[...]
Maybe there's a way to calculate (UINT_MAX + 1)/(UCHAR_MAX + 1)
without risking zero in the numerator and/or denominator, but I
haven't figured one out. (Note that UCHAR_MAX == ULLONG_MAX is
permitted by the Standard.)

Since UCHAR_MAX <= UINT_MAX <= ULLONG_MAX...

#if UCHAR_MAX == ULLONG_MAX
# define UINT_UCHAR_RATIO 1
#else
# define UINT_UCHAR_RATIO \
(((unsigned long long)UINT_MAX + 1) / \
((unsigned long long)UCHAR_MAX + 1))
#endif

If UINT_MAX == ULLONG_MAX, this yields a ratio
of zero.
 
P

Peter Nilsson

Eric said:
bd said:
Eric Sosman wrote:
[...]
Maybe there's a way to calculate (UINT_MAX + 1)/(UCHAR_MAX + 1)
without risking zero in the numerator and/or denominator, but I
haven't figured one out. (Note that UCHAR_MAX == ULLONG_MAX is
permitted by the Standard.)

Since UCHAR_MAX <= UINT_MAX <= ULLONG_MAX...

#if UCHAR_MAX == ULLONG_MAX
# define UINT_UCHAR_RATIO 1
#else
# define UINT_UCHAR_RATIO \
(((unsigned long long)UINT_MAX + 1) / \
((unsigned long long)UCHAR_MAX + 1))
#endif

If UINT_MAX == ULLONG_MAX, this yields a ratio
of zero.

I'm not sure why you need this ratio, but it's trivial to calculate...
(UINT_MAX/2+1) / (UCHAR_MAX/2+1)
 
E

Eric Sosman

Peter said:
Eric said:
bd said:
Eric Sosman wrote:
[...]

Maybe there's a way to calculate (UINT_MAX + 1)/(UCHAR_MAX + 1)
without risking zero in the numerator and/or denominator, but I
haven't figured one out. [...]

I'm not sure why you need this ratio, but it's trivial to calculate...
(UINT_MAX/2+1) / (UCHAR_MAX/2+1)

<Self-administers a dope slap> Duhh ...

The ratio was to be used to solve the problem posed
(oh, so long ago) at the beginning of this thread: Write
fully portable code to left-adjust an `unsigned char' in
an `unsigned int'. Everybody (self included) got caught
up in trying to come up with a recipe using shifts, and
ran afoul of one or more of padding bits, shift counts too
wide for shifted operand, or uncommon relationships among
the various Uxxx_MAX values. The correct solutions offered
thus far involve ugly loops; "ugly" because they perform
a calculation at run time that any particular compiler
could have done during compilation.

Having the ratio available makes the problem easy:

unsigned char uc = ...;
unsigned int ui = uc
* ((UINT_MAX/2+1)/(UCHAR_MAX/2+1));

"Mainstream" implementations will calculate the ratio
as 2**N (N >= 1) and probably replace the multiplication
with a shift, while "exotic" implementations will get a
ratio of unity and probably eliminate the multiplication
altogether.
 
P

Peter Nilsson

Eric said:
The ratio was to be used to solve the problem posed
(oh, so long ago) at the beginning of this thread: Write
fully portable code to left-adjust an `unsigned char' in
an `unsigned int'. Everybody (self included) got caught
up in trying to come up with a recipe using shifts, and
ran afoul of one or more of padding bits, shift counts too
wide for shifted operand, or uncommon relationships among
the various Uxxx_MAX values. The correct solutions offered
thus far involve ugly loops; "ugly" because they perform
a calculation at run time that any particular compiler
could have done during compilation.

Perhaps your newsserver didn't receive the early offering...

#include <limits.h>

#define move_uc_to_umsb(u,uc) \
((((unsigned )(u )) & (-1u >> (CHAR_BIT - 1) >> 1) ) \
|(((unsigned char)(uc)) * ((-1u >> (CHAR_BIT - 1) >> 1) + 1)))
Having the ratio available makes the problem easy:

unsigned char uc = ...;
unsigned int ui = uc
* ((UINT_MAX/2+1)/(UCHAR_MAX/2+1));

"Mainstream" implementations will calculate the ratio
as 2**N (N >= 1) and probably replace the multiplication
with a shift, while "exotic" implementations will get a
ratio of unity and probably eliminate the multiplication
altogether.

I don't think many people know about the x >> (N - 1) >> 1 option
of avoiding the undefined behaviour when N might be the width of x.
[Assuming that x '>>' N == 0 is the prefered option in such cases.]
 
D

Dave Thompson

On Fri, 14 Jan 2005 09:10:30 -0500, Eric Sosman
Shifting by zero bits is even more pointless, but that
doesn't seem to have prompted instruction-set designers to
omit the operation (unless they also omit all multi-bit
shifts; I've used machines whose only shift instructions
were single-bit shifts).
And the PDP-8 (and 12?) had rotate-by-1 and by-2, only; "through" the
Link ~ carry bit, which could be cleared or set to produce an
effective shift. Well, and (at least on some models?) byte-swap for
6-bit bytes.

(Since the zero-bit shift also seems useless, I imagine a
designer might decide to use the opcode that resembles "shift
by zero" to denote some entirely different operation. <snip>

Not 'entirely different', but on Tandem^WCompaq^WHP NonStop,
{,Dbl}{Log,Arith}{Left,Right}Shift operand 1 to 31 meant a constant
shift while 0 meant variable shift determined by (and consuming) an
additional register-stack value, which may itself be 0.

- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,159
Messages
2,570,879
Members
47,414
Latest member
GayleWedel

Latest Threads

Top