title: Converting between DEC(base 10) and HEX(base 16) using two's complement
body: <p>As the title says I need to make a function that converts between the 2 bases, DEC and HEX in twos complement. The number of bits the value uses is known from the start. </p>
  
  <p>After doing more than a little digging around i found the following algorithm:</p>
  
  <ol>
  <li>Given a number in DEC.</li>
  <li>Get the absolute value of the number.</li>
  <li>Get the binary(BIN) value of the abs from step 2.</li>
  <li>Pad with <code>0</code>s on the left until the number is the desired length.</li>
  <li><code>NOT</code> all the bits obtained in step 4.</li>
  <li>Add 1 to the result. (Easiest way in practice is probably to convert back to DEC, add 1, and back to BIN)</li>
  <li>Convert to HEX. Done.</li>
  </ol>
  
  <p>This algorithm from what I observer might only work if the original number is negative(&lt;0). I managed to get results that seem correct by making the following modification: </p>
  
  <p>On step 6, don't add 1. Instead add the opposite of the signature of the original number. For example if the original number was negative, like <code>-455</code> then add <code>1</code>, if it was positive, like <code>10002</code> then "add" <code>-1</code>. </p>
  
  <p>This does seem to give positive results but I'm not sure about it's soundness as I have never worked with two's complement before this and this modification to step 6 was in my view <code>logic + guesswork - formal_knowledge</code>.</p>
  
  <p>Here is the Python 3.6 function I came up with, the DEC value is an int, all other values are represented as strings, the desired length i assumed was just the next multiple of 4:</p>
  
  <pre><code>def d2h(i: int) -&gt; str:
          sign  = (i // abs(i)) if i is not 0 else 1
          step1 = i
          step2 = abs(step1)
          step3 = bin(step2)[2:]
          step4 = step3
          while len(step4) % 4 != 0:
                  step4 = '0' + step4
          step5 = step4.replace('0', 'O') \
                       .replace('1', '0') \
                       .replace('O', '1')
          step6 = bin(int(step5, 2) + -sign)[2:]
          step7 = hex(int(step6, 2))[2:]
          return step7
  </code></pre>
  
  <p>As for converting back, from a HEX value to a DEC one, what I managed to kind of "reverse engineer"(as I was not able to find something that actually explained this):</p>
  
  <ol>
  <li>Given a number in HEX.</li>
  <li>Get it's representation in binary, BIN.</li>
  <li>Pad with <code>0</code> until the desired length.</li>
  <li>Check if the leftmost bit is <code>1</code>(a.k.a. the number is negative). </li>
  <li>If the number is negative, then convert the BIN value from step 3 to DEC and then subtract 2 to the power of however many bits we have( <code>2 ^ len(BIN)</code> ), if the number is NOT negative(the leading bit is <code>0</code>) then simply convert it to DEC like usual. Done.</li>
  </ol>
  
  <p>Here is the Python function I wrote for that(same implementation details as above):</p>
  
  <pre><code>def h2d(h: str) -&gt; int:
          step1 = h
          step2 = bin(int(h, 16))[2:]
          step3 = step2
          while len(step3) % 4 != 0:
                  step3 = '0' + step3
          if step3[0] == '1':
                  step4 = int(step3, 2) - (2**len(step3))
          else:
                  step4 = int(step3, 2)
          return step4
  </code></pre>
  
  <p>My bottom question is: Will these functions convert any number to and from two's complement in HEX correctly or did I just stumble into a coincidence of lucky test values?  Is this correct? </p>
  
  <p>EDIT: Upon further testing I have found that <code>h2d(d2h())</code> does not always give the correct values. For numbers such as 0, 1, 2, etc. it gives the negative values -2, -3, -4, etc. but for the border cases, -32768 and 32767 it works. </p>
  
  <p>Since it is obviously incorrect now, what should I change(for both algorithms) so that they would be correct?</p>
  
  <p>Thank you in advance!</p>