3

I have an array of hex positive and negetive numbers. I want to transform them to decimal value:

>>> int("f107",16)
61703
>>> 

how can I make python to look f107 as a two's complemented number? In the other word I want -3833 instead of 61703. How can I achieve it?

Ebrahim Ghasemi
  • 5,850
  • 10
  • 52
  • 113

2 Answers2

4

It's a very simple function:

def twos_complement(n, w):
    if n & (1 << (w - 1)): n = n - (1 << w)
    return n

Example:

>>> twos_complement(61703, 16)
-3833

Unlike Joran's answer this supports arbitrary bit-width.

orlp
  • 112,504
  • 36
  • 218
  • 315
  • 1
    great answer :) although you still have to pass in the width(I think you could calculate it with logs and stuff) ... but its cool that you could use weird non standard widths – Joran Beasley Nov 15 '15 at 04:55
  • If your function took the "f107" hex string as its arg it could calculate the required width of the bitmask... – PM 2Ring Nov 15 '15 at 04:57
  • @JoranBeasley You can't calculate the width. Compare `twos_complement(5, 3)` with `twos_complement(5, 4)`. One is simply 5, but in the other width's it's -3. You have to give the width explicitly to interpret numbers as two's complement. – orlp Nov 15 '15 at 04:57
  • @PM2Ring You can build that function using this one, but not the other way around :) This is more general. – orlp Nov 15 '15 at 04:58
  • @JoranBeasley Excuse me I didn't got the point about `width`. May I ask to explain a little more?(_have to pass in the width_) – Ebrahim Ghasemi Nov 15 '15 at 04:58
  • 3
    @Abraham A two's complement number has a width. For example a 32-bit number, or a 16-bit number. The number you gave in your question is a 16-bit number. The actual value of the number depends on the width. – orlp Nov 15 '15 at 04:59
  • 1
    @Abraham: It's a little tricky doing this stuff in Python. Unlike in C, where you have various fixed sized integers, Python's integers are of arbitrary size: they're as big as they need to be. So when you want to use some form of complement notation to represent negative quantities you need to specify the width. – PM 2Ring Nov 15 '15 at 05:04
3
struct.unpack(">h","f107".decode("hex"))

0xf107 = encode_to_bytes => "\xf1\x07"

since its two bytes we simply unpack it as > big-endian h signed-short

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179