def ALU16(x, y, zx, nx, zy, ny, f, no):
    n = 16
    output = [random.randint(0,1) for i in range(n)] # Random noise in bits
    print("current output (noise or leftover) = ", output)
    G.sizeCheckn(output, output, n)

    # Condition 1
    if zx == 1: x = Zero16(x)
    else: pass # x does not change

    # Condition 2
    if nx == 1: x = G.NOT16(x)
    else: pass

    # Condition 3
    if zy == 1: y = Zero16(y)
    else: pass # y does not change

    # Condition 4
    if ny == 1: y = G.NOT16(y)
    else: pass

    # Condition 5
    if f == 1: output = G.Add16(x, y) 
    else: output = G.AND16(x, y)

    # Condition 6
    if no == 1: output = G.NOT16(output)
    else: pass

    return output
	def clock(self, nex, load, address): 
		G.sizeCheckn(nex, nex, self.n); G.checkBit(load)
		for next in address:
			G.checkBit(int(next))
		if len(address) > self.k:
			sys.exit("THE NUMBER OF BITS IN ADDRESS IS NOT LESS THAN THE NUMBER OF REGISTERS. ABORTING THE MISSION!")
		output = self.registers[address].clock(nex, load)
		return output
	def __init__(self, a, address, r):
		self.k = math.log(r,2)
		if len(address) != self.k:
			sys.exit("THE NUMBER OF BITS IN ADDRESS DOES NOT MATCH WITH THE NUMBER OF REGISTERS. ABORTING THE MISSION!")
		self.n = 16
		G.sizeCheckn(a, a, self.n)
		self.registers = {}
		for i in range(r):
			den = np.binary_repr(i, int(self.k))
			self.registers[den] = REGISTER([random.randint(0, 1) for i in range(self.n)])
		self.registers[address] = REGISTER(a)
	def clock(self, nex, load):
		G.sizeCheckn(nex, nex, self.n); G.checkBit(load)
		output = []
		for i in range(self.n):
			output.append(self.BITs[i].clock(nex[i], load))
		return output
	def __init__(self, a):
		self.n = 16
		G.sizeCheckn(a, a, self.n)
		self.BITs = []
		for i in range(self.n):
			self.BITs.append(BIT(a[i]))