views:

205

answers:

4

Hi.

I was reading the source of GNU PDF library, particularly their implementation of 64 bit integers. They have defined 64 bit integers as structs of two 32 bit integers - the higher order int is signed and lower order int is unsigned. Here's the relevant code from the header file:

/*Definition of internal structure of the pdf_i64_t type*/
struct pdf_i64_s
{
  pdf_i32_t   high;
  pdf_u32_t low;
};

typedef struct pdf_i64_s pdf_i64_t;

According to the architecture manual negative numbers are represented in two's complement form. I have a doubt regarding this function though:

[code from pdf-types.c]

void pdf_i64_assign_quick (pdf_i64_t *bignum,
                      const pdf_i32_t value,
                  pdf_status_t *p_status)
{
  ASSIGN_SAFE(p_status, PDF_OK);

  if (bignum != NULL)
    {
      if (value < 0)
        {
          bignum->high = 0xFFFFFFFF;
        }
      else
        {
          bignum->high = 0;
        }
      bignum->low = value;
    }
  else
    {
      ASSIGN_SAFE(p_status, PDF_ERROR);
    }
}

From what I read, to get the two's complement of a number, you need to invert all the bits and add 1 to the result. In the above function though, for value<0 they are only setting the higher order bits to 0xFFFFFFFF but not changing the lower order bits at all. Shouldn't the bits of 'value' be inverted too, followed by the addition of 1? Can someone explain this?

Thanks.

+5  A: 

You'll note that value is already a signed 32-bit integer - if it's negative, it's already been inverted appropriately. All that needs to be done is the sign-extension.

Anon.
A: 

It says there that value is a 32 bit int...value would already be in 2s complement form so no need to change

Charles Ma
+2  A: 

I think you're mixing up a few things -- to negate a number in two's complement notation, you flip all the bits and add one.

There's no negation here though. This is storing a value, and doing sign extension -- the top bits has to be extended through the upper 32 bits. This is what's going on, since the input is already signed, two's complement input.

Sean Owen
+1  A: 

Anon already answered this, I just wanted to post a slight optimization that does exactly the same thing without branching.

void pdf_i64_assign_quick (pdf_i64_t *bignum,
                      const pdf_i32_t value,
                  pdf_status_t *p_status)
{
  ASSIGN_SAFE(p_status, PDF_OK);

  if (bignum != NULL)
    {
      bignum->high = (value >= 0) - 1;
      bignum->low = value;
    }
  else
    {
      ASSIGN_SAFE(p_status, PDF_ERROR);
    }
}

0xffffffff is 32 bit hex for -1 and (value >= 0) evaluates to either 1 or 0, so it also sets high to 0xffffffff for negative values of value and to 0 for positive values.

x4u