Velocity Reviews > Is this a guaranteed signed/unsigned conversion?

# Is this a guaranteed signed/unsigned conversion?

CBFalconer
Guest
Posts: n/a

 05-20-2005
Consider:

#include <stdlib.h>

/* An elementary optimizer is expected to remove most code */
/* Return the absolute value */
unsigned long ulabs(long j)
{
if (0 == LONG_MIN + LONG_MAX) {
if (j < 0) return -j;
else return j;
}
else if (LONG_MIN == j) return 1U + j + ULONG_MAX;
else if (j < 0) return -j;
else return j;
} /* ulabs */

Is this guaranteed to convert all long values to their absolute
unsigned long equivalent, assuming that the desired result is
representable as an unsigned long. Does it work over 2's, 1's
complement and sign-magnitude? Is there a better method? labs()
is not guaranteed.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the

Michael Mair
Guest
Posts: n/a

 05-20-2005
CBFalconer wrote:
> Consider:
>
> #include <stdlib.h>
>
> /* An elementary optimizer is expected to remove most code */
> /* Return the absolute value */
> unsigned long ulabs(long j)
> {
> if (0 == LONG_MIN + LONG_MAX) {

Make that <=
> if (j < 0) return -j;
> else return j;
> }
> else if (LONG_MIN == j) return 1U + j + ULONG_MAX;

why not:
else if (j>0)
return j;
else if (j>= -LONG_MAX)
return -j;
else
return ((unsigned long)-(j-(LONG_MIN+LONG_MAX)))-(LONG_MIN+LONG_MAX);
> else if (j < 0) return -j;
> else return j;
> } /* ulabs */
>
> Is this guaranteed to convert all long values to their absolute
> unsigned long equivalent, assuming that the desired result is
> representable as an unsigned long. Does it work over 2's, 1's
> complement and sign-magnitude? Is there a better method? labs()
> is not guaranteed.

If you assume that all bits are used and symmetrically, your
code will work.
Otherwise: what about LONG_MIN < -LONG_MAX-1?

See my annotations. (Burned my dinner over it, so I hope I
did not goof )

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.

Eric Sosman
Guest
Posts: n/a

 05-20-2005

CBFalconer wrote:
> Consider:
>
> #include <stdlib.h>
>
> /* An elementary optimizer is expected to remove most code */
> /* Return the absolute value */
> unsigned long ulabs(long j)
> {
> if (0 == LONG_MIN + LONG_MAX) {
> if (j < 0) return -j;
> else return j;
> }
> else if (LONG_MIN == j) return 1U + j + ULONG_MAX;
> else if (j < 0) return -j;
> else return j;
> } /* ulabs */
>
> Is this guaranteed to convert all long values to their absolute
> unsigned long equivalent, assuming that the desired result is
> representable as an unsigned long. Does it work over 2's, 1's
> complement and sign-magnitude? Is there a better method? labs()
> is not guaranteed.

Let's see: The first part handles ones' complement and
signed magnitude, where negation of LONG_MIN is possible.
Straightforward, and correct as far as I can see. By the
way, the `0 == LONG_MIN + LONG_MAX' test could be made
with `#if' instead of with `if', reducing the reliance on
the optimizer's ability to eliminate dead code.

In the two's complement part, the conversion of LONG_MIN
seems wordier than need be: as far as I can tell, it gives
the same result as `return j'. Either way, the result should
be correct if ULONG_MAX == LONG_MAX * 2UL + 1UL, which is the
case on every implementation I've run into. However, I think
the Standard permits perversity, and two kinds of perversity
could cause trouble:

ULONG_MAX == LONG_MAX (that is, the sign bit of
`long' corresponds to a padding bit in `unsigned
long'). In this case your quest is hopeless --
but your assumption excludes it, so perhaps we
needn't worry. Another #if could trigger an
appropriate #error directive if desired.

ULONG_MAX == LONG_MAX * 4UL + 3UL (for example;
this happens if `long' has padding bits that
correspond to value bits of `unsigned long').
In this case, ulabs() would return much too
large a value.

I think there's a simple repair, though. For a negative
two's complement value, first add unity, then negate (this is
known to be safe), then convert to `unsigned long', and finally

if (j < 0) return -(j + 1) + 1UL;
else return j;

(Note that the first `return' expression is *not* equivalent
to `1UL - (j + 1)', because the conversion to `unsigned long'
occurs at the wrong point in the proceedings. I'd recommend
a goodly block of comments here to discourage tidy-minded
people from making the "obvious" rearrangement -- either that,
or write it as `-++j+1UL' to scare them all away.

As far as I can see, this will cover all cases except
ULONG_MAX == LONG_MAX, already excluded by assumption. It
would even handle ones' complement and signed magnitude,
eliminating the special case at the cost of a smidgen of
unnecessary code.

Of course, I may have overlooked something. "Trust,
but verify."

--

Christian Bau
Guest
Posts: n/a

 05-20-2005
In article <>,
CBFalconer <> wrote:

> Consider:
>
> #include <stdlib.h>
>
> /* An elementary optimizer is expected to remove most code */
> /* Return the absolute value */
> unsigned long ulabs(long j)
> {
> if (0 == LONG_MIN + LONG_MAX) {
> if (j < 0) return -j;
> else return j;
> }
> else if (LONG_MIN == j) return 1U + j + ULONG_MAX;
> else if (j < 0) return -j;
> else return j;
> } /* ulabs */
>
> Is this guaranteed to convert all long values to their absolute
> unsigned long equivalent, assuming that the desired result is
> representable as an unsigned long. Does it work over 2's, 1's
> complement and sign-magnitude? Is there a better method? labs()
> is not guaranteed.

I think it will work; I believe it is guaranteed that LONG_MIN +
LONG_MAX is either 0 or -1.

unsigned long ulabs (long j) {
return j >= 0 ? (unsigned long) j : 0ul - j;
}

I think this should work. The case j >= 0 is obviously fine. If j < 0,
then evaluating (0ul - j) will convert j to unsigned long; since the
value of j cannot be represented ULONG_MAX + 1 will be added as often as
needed (that is once) giving (j + ULONG_MAX + 1). The subtract operation
gives - (j + ULONG_MAX + 1) and since the result is negative, ULONG_MAX
+ 1 is again added as often as necessary (that is once), giving -j.

Lawrence Kirby
Guest
Posts: n/a

 05-21-2005
On Fri, 20 May 2005 20:08:26 +0000, CBFalconer wrote:

> Consider:
>
> #include <stdlib.h>
>
> /* An elementary optimizer is expected to remove most code */
> /* Return the absolute value */
> unsigned long ulabs(long j)
> {
> if (0 == LONG_MIN + LONG_MAX) {
> if (j < 0) return -j;
> else return j;
> }
> else if (LONG_MIN == j) return 1U + j + ULONG_MAX;

That's incorrect if ULONG_MAX is over twice as large as LONG_MAX.
Why not just return 1UL + LONG_MAX.

> else if (j < 0) return -j;
> else return j;
> } /* ulabs */
>
> Is this guaranteed to convert all long values to their absolute
> unsigned long equivalent, assuming that the desired result is
> representable as an unsigned long. Does it work over 2's, 1's
> complement and sign-magnitude? Is there a better method? labs()
> is not guaranteed.

I've used similar to the following in the past:

unsigned long ulabs(long j)
{
return j>=0 ? (unsigned long)j : -(unsigned long)j;
}

Lawrence

Simon Biber
Guest
Posts: n/a

 05-21-2005
Lawrence Kirby wrote:
> I've used similar to the following in the past:
>
> unsigned long ulabs(long j)
> {
> return j>=0 ? (unsigned long)j : -(unsigned long)j;
> }

I wonder if anyone ever made a C implementation that allows you to
choose at compile-time whether integers are stored as one's complement,
two's complement or signed magnitude? Of course, emulating operations on
a data type that is not native to the underlying hardware would be very
slow, but I imagine it would be useful for testing your code's
portability to esoteric computers without having them available on the
desktop.

The closest I know of is how GCC allows you to choose whether char is
signed or unsigned.

--
Simon.

CBFalconer
Guest
Posts: n/a

 05-22-2005
Lawrence Kirby wrote:
> On Fri, 20 May 2005 20:08:26 +0000, CBFalconer wrote:
>

.... snip ...
>>
>> Is this guaranteed to convert all long values to their absolute
>> unsigned long equivalent, assuming that the desired result is
>> representable as an unsigned long. Does it work over 2's, 1's
>> complement and sign-magnitude? Is there a better method? labs()
>> is not guaranteed.

>
> I've used similar to the following in the past:
>
> unsigned long ulabs(long j)
> {
> return j>=0 ? (unsigned long)j : -(unsigned long)j;
> }

I can see nothing wrong with that. Why did I make it so
complicated?

--
news:news.announce.newusers
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html

Malcolm
Guest
Posts: n/a

 05-22-2005

"Simon Biber" <> wrote
> I wonder if anyone ever made a C implementation that allows you to choose
> at compile-time whether integers are stored as one's complement, two's
> complement or signed magnitude?

That would be a really useful tool. Something that compiles C to byte code,
and then produces output based on all sorts of configurable and maybe