3

How can I do a logical NAND on two numbers in python? Simple example. Let's say I have a number (0xFF) and I want a logical NAND with a mask value of 0x5.

number = 0xFF = 0b1111 1111
mask   = 0x05 = 0b0000 0101
---------------------------
desired= 0xFA = 0b1111 1010

I'm not reinventing the wheel here, this seems like it should be easily accomplished, but I'm stumped and I cannot find any solutions online. I can loop through the number and do a "not (number & mask)" at each bit position and reassemble the value I want, but that seems like more work than is needed here.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
milnuts
  • 407
  • 2
  • 7
  • 16
  • 1
    A python integer is [unbounded](https://stackoverflow.com/a/7604981/1424875) - how do you want the infinite/colossal number of leading (1) bits handled when you NAND two numbers (which conceptually have an infinite/colossal number of leading (0) bits)? – nanofarad Jan 19 '23 at 20:56
  • 3
    What would be the result of NAND of 0x0FF and 0x005, given that 0 NAND 0 is 1? Then ask yourself why it would be different from your example, since the numbers are actually the same... – trincot Jan 19 '23 at 20:56
  • trincot, ok, i see the problem there. so i really do have to write a function to loop only on the length of my "number" and not the infinite amount of leading digits – milnuts Jan 19 '23 at 21:06
  • 1
    That depends what is the determining factor: is it really the length of the number? Is it always a power of 2 minus 1? Or could it be any number, and then which bits will you actually count? – trincot Jan 19 '23 at 21:07
  • 3
    What you're describing here is a bitwise NAND, not a logical NAND. – user2357112 Jan 19 '23 at 21:09
  • 1
    @nanofarad like Python already implements bitwise not: the sign bit acts as the infinite digits on the left. If you want to truncate your calculation to N bits you can just do e.g. `(result + (1< – Matteo Italia Jan 19 '23 at 22:24

1 Answers1

1

Python integers have arbitrary length, so taking their NAND doesn't really make sense where they have implicit leading 0s. Plus, they're signed, so bitwise NOT (~) returns the two's complement.

What you can do instead is use a NumPy unsigned type, assuming the numbers fit. In this case, uint8:

import numpy as np

number = np.uint8(0xff)
mask = np.uint8(0x05)

result = ~(number & mask)

for n in number, mask, result:
    print(f'0x{n:02X} 0b{n:08b}')

Output:

0xFF 0b11111111
0x05 0b00000101
0xFA 0b11111010

Other NumPy sized data types are listed here.

wjandrea
  • 28,235
  • 9
  • 60
  • 81