def _float_binary_operator(self, term, op): logger.debug('_fbo: %s\n%s', term, self.attrs[term]) x = self.eval(term.x) y = self.eval(term.y) z = op(x, y) conds = [] if 'nnan' in self.attrs[term]: df = z3.And(z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(z))) conds.append(z3.Implies(self.attrs[term]['nnan'], df)) elif 'nnan' in term.flags: conds += [ z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(z)) ] if 'ninf' in self.attrs[term]: df = z3.And(z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(z))) conds.append(z3.Implies(self.attrs[term]['ninf'], df)) elif 'ninf' in term.flags: conds += [ z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(z)) ] if 'nsz' in self.attrs[term] or 'nsz' in term.flags: # NOTE: this will return a different qvar for each (in)direct reference # to this term. Is this desirable? b = self.fresh_bool() self.add_qvar(b) z = op(x, y) c = z3.fpIsZero(z) if 'nsz' in self.attrs[term]: c = z3.And(self.attrs[term]['nsz'], c) s = _ty_sort(self.type(term)) z = z3.If(c, z3.If(b, 0, z3.fpMinusZero(s)), z) if isinstance(term, FDivInst): c = [z3.Not(z3.fpIsZero(x)), z3.fpIsZero(y)] if 'nsz' in self.attrs[term]: c.append(self.attrs[term]['nsz']) z = z3.If( z3.And(c), z3.If(b, z3.fpPlusInfinity(s), z3.fpMinusInfinity(s)), z) return self._conditional_value(conds, z, term.name)
def _float_binary_operator(self, term, op): logger.debug('_fbo: %s\n%s', term, self.attrs[term]) x = self.eval(term.x) y = self.eval(term.y) z = op(x,y) conds = [] if 'nnan' in self.attrs[term]: df = z3.And(z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(z))) conds.append(z3.Implies(self.attrs[term]['nnan'], df)) elif 'nnan' in term.flags: conds += [z3.Not(z3.fpIsNaN(x)), z3.Not(z3.fpIsNaN(y)), z3.Not(z3.fpIsNaN(z))] if 'ninf' in self.attrs[term]: df = z3.And(z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(z))) conds.append(z3.Implies(self.attrs[term]['ninf'], df)) elif 'ninf' in term.flags: conds += [z3.Not(z3.fpIsInf(x)), z3.Not(z3.fpIsInf(y)), z3.Not(z3.fpIsInf(z))] if 'nsz' in self.attrs[term] or 'nsz' in term.flags: # NOTE: this will return a different qvar for each (in)direct reference # to this term. Is this desirable? b = self.fresh_bool() self.add_qvar(b) z = op(x,y) c = z3.fpIsZero(z) if 'nsz' in self.attrs[term]: c = z3.And(self.attrs[term]['nsz'], c) s = _ty_sort(self.type(term)) z = z3.If(c, z3.If(b, 0, z3.fpMinusZero(s)), z) if isinstance(term, FDivInst): c = [z3.Not(z3.fpIsZero(x)), z3.fpIsZero(y)] if 'nsz' in self.attrs[term]: c.append(self.attrs[term]['nsz']) z = z3.If(z3.And(c), z3.If(b, z3.fpPlusInfinity(s), z3.fpMinusInfinity(s)), z) return self._conditional_value(conds, z, term.name)
def _(src, tgt, v): w = z3.fpToIEEEBV(v) i = z3.If(z3.Or(z3.fpIsZero(v), z3.fpIsSubnormal(v)), z3.BitVecVal(0,1), z3.BitVecVal(1,1)) return z3.Concat(z3.Extract(78,63,w), i, z3.Extract(62,0,w))
s = z3.Solver() # C must be a power of 2, i.e. significand bits must all be 0. s.add(z3.Extract(FLOAT_TY().sbits() - 1, 0, z3.fpToIEEEBV(c)) == 0) for rm in [z3.RTZ(), z3.RNE()]: z3.set_default_rounding_mode(rm) before = a * c + b * c after = (a + b) * c # Check that before == after, allowing that 0 == -0. s.add( z3.Not( z3.Or( before == after, # z3.And(z3.fpIsZero(before), z3.fpIsZero(after))))) for x in [ (a * c), (b * c), (a + b), ]: s.add(z3.Not(z3.fpIsSubnormal(x))) s.add(z3.Not(z3.fpIsZero(x))) s.add(z3.Not(z3.fpIsInf(x))) if s.check() == z3.sat: m = s.model() print("Counterexample found!") print(m) print("a*c: ", z3.simplify(m[a] * m[c]))