unsigned abs(int)?

Discussion in 'C Programming' started by Stefan Ram, Jun 29, 2012.

  1. Stefan Ram

    Stefan Ram Guest

    (This might be an FAQ.) What is the portable way, if any, to
    define a function

    unsigned abs( int )

    that returns the correct value especially also for INT_MIN?
    »Portable« includes that it works both with two's-complement
    and with one's-complement representation and with any ranges
    of int and unsigned permitted by C.
    Stefan Ram, Jun 29, 2012
    #1
    1. Advertising

  2. -berlin.de (Stefan Ram) writes:

    > (This might be an FAQ.) What is the portable way, if any, to
    > define a function
    >
    > unsigned abs( int )
    >
    > that returns the correct value especially also for INT_MIN?
    > »Portable« includes that it works both with two's-complement
    > and with one's-complement representation and with any ranges
    > of int and unsigned permitted by C.


    C allows and implementation in which UINT_MAX == INT_MAX and where,
    simultaneously, -INT_MAX > INT_MIN (indeed such implementations exist).
    As a result, the mathematical value of abs(INT_MIN) need not be
    representable as an unsigned int. I don't think an entirely portable,
    correct function exists with the given prototype.

    --
    Ben.
    Ben Bacarisse, Jun 29, 2012
    #2
    1. Advertising

  3. Stefan Ram

    Tim Rentsch Guest

    -berlin.de (Stefan Ram) writes:

    > (This might be an FAQ.) What is the portable way, if any, to
    > define a function
    >
    > unsigned abs( int )
    >
    > that returns the correct value especially also for INT_MIN?
    > >>Portable<< includes that it works both with two's-complement

    > and with one's-complement representation and with any ranges
    > of int and unsigned permitted by C.


    unsigned
    unsigned_abs( int n ){
    return n >= 0 ? n : -(n+1) + 1UL;
    }

    Note that for implementations where UINT_MAX == INT_MAX,
    and where INT_MIN == -INT_MAX - 1 (which must be two's
    complement), there is no unsigned int value that's right.
    Under these conditions, unsigned_abs( INT_MIN ) gives zero.
    In all other cases it gives the right value.

    (Am I confused or is abs() the name of a standard library
    function?)
    Tim Rentsch, Jun 29, 2012
    #3
  4. Stefan Ram

    Stefan Ram Guest

    Tim Rentsch <> writes:
    >unsigned
    >unsigned_abs( int n ){
    > return n >= 0 ? n : -(n+1) + 1UL;
    >}
    >Note that for implementations where UINT_MAX == INT_MAX,
    >and where INT_MIN == -INT_MAX - 1 (which must be two's
    >complement), there is no unsigned int value that's right.
    >Under these conditions, unsigned_abs( INT_MIN ) gives zero.
    >In all other cases it gives the right value.


    I was asking because some implementations of »itoa« start
    with something like:

    if( n < 0 ){ n = -n; *p++ = '-'; }

    , but then seem to fail sometimes for INT_MIN.

    I was wondering whether there is a portable implementation
    that will be correct for all int values.

    One could set a flag when n == INT_MIN and then
    convert (n+1). Eventually one would do the »+1«
    on the string buffer, possibly with a carry value.

    >(Am I confused or is abs() the name of a standard library
    >function?)


    Well, let's say that, er, I was thinking of a freestanding
    implementation.
    Stefan Ram, Jul 1, 2012
    #4
  5. Stefan Ram

    Eric Sosman Guest

    On 7/1/2012 2:27 PM, Stefan Ram wrote:
    > Tim Rentsch <> writes:
    >> unsigned
    >> unsigned_abs( int n ){
    >> return n >= 0 ? n : -(n+1) + 1UL;
    >> }
    >> Note that for implementations where UINT_MAX == INT_MAX,
    >> and where INT_MIN == -INT_MAX - 1 (which must be two's
    >> complement), there is no unsigned int value that's right.
    >> Under these conditions, unsigned_abs( INT_MIN ) gives zero.
    >> In all other cases it gives the right value.

    >
    > I was asking because some implementations of »itoa« start
    > with something like:
    >
    > if( n < 0 ){ n = -n; *p++ = '-'; }
    >
    > , but then seem to fail sometimes for INT_MIN.
    >
    > I was wondering whether there is a portable implementation
    > that will be correct for all int values.


    PJ Plauger's "The Standard C Library" shows one way to handle
    the task, in the underpinnings of printf() et al. Basically, he
    converts a negative value to `unsigned long', negates that value
    in `unsigned long' arithmetic, and uses the result to produce the
    leading digit. Then he strips the leading digit from the value
    being converted (without the leading digit it must be >LONG_MIN)
    and proceeds straightforwardly through any remaining digits.

    Another way would be to start with something like

    if (n > 0) n = -n; else *p++ = '-';

    .... and work in negative numbers all the way. This is a little
    trickier in C90 than in C99/C11, because in the former `-13 % 10'
    could be -3 or +7, while in the later Standards it is always -3.

    --
    Eric Sosman
    d
    Eric Sosman, Jul 1, 2012
    #5
  6. Stefan Ram

    Tim Rentsch Guest

    -berlin.de (Stefan Ram) writes:

    > Tim Rentsch <> writes:
    >>unsigned
    >>unsigned_abs( int n ){
    >> return n >= 0 ? n : -(n+1) + 1UL;
    >>}
    >>Note that for implementations where UINT_MAX == INT_MAX,
    >>and where INT_MIN == -INT_MAX - 1 (which must be two's
    >>complement), there is no unsigned int value that's right.
    >>Under these conditions, unsigned_abs( INT_MIN ) gives zero.
    >>In all other cases it gives the right value.

    >
    > I was asking because some implementations of >>itoa<< start
    > with something like:
    >
    > if( n < 0 ){ n = -n; *p++ = '-'; }
    >
    > , but then seem to fail sometimes for INT_MIN.
    >
    > I was wondering whether there is a portable implementation
    > that will be correct for all int values. [snip]


    void
    simple_itoa( int n, char *s ){
    enum { D = 1 + CHAR_BIT*sizeof(int)/3 };
    char buffer[D+1], *p = buffer + D;
    *p = 0;

    if( n < 0 ) *s++ = '-';
    if( n > 0 ) n = -n;

    while( n < -9 ){
    int r = -(n+10)%10;
    *--p = '0' + r;
    n = (n+r)/10;
    }
    *--p = '0' + -n;

    strcpy( s, p );
    }


    1. Works for all int values.

    2. No casting or other types needed (and so no dependencies
    on ranges of any other types).

    3. No checks for "unusual" values.

    4. Same results under both C90 and C99 (and C11) semantics.

    5. (The expression computing a value for 'D' can be
    improved, but the one here is probably good enough
    in most cases.)


    The code above may be used freely for any purpose subject
    only to the condition that it not be claimed as original
    work, ie, by anyone other than me. (And especially not
    by any patent trolls out there...)
    Tim Rentsch, Jul 2, 2012
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Timo Freiberger
    Replies:
    3
    Views:
    923
    Bob Hairgrove
    Oct 30, 2004
  2. Klaas Vantournhout

    f2c's abs conflicts with <complex> abs

    Klaas Vantournhout, Oct 31, 2006, in forum: C++
    Replies:
    3
    Views:
    375
    Victor Bazarov
    Oct 31, 2006
  3. er
    Replies:
    6
    Views:
    472
    Andre Kostur
    Sep 14, 2007
  4. ciccio

    int*unsigned int = unsigned?

    ciccio, Jun 4, 2010, in forum: C++
    Replies:
    2
    Views:
    390
    Öö Tiib
    Jun 4, 2010
  5. pozz
    Replies:
    12
    Views:
    714
    Tim Rentsch
    Mar 20, 2011
Loading...

Share This Page