Theory of Floating-Points

examples/api/cpp/floating_point_arith.cpp

  1 /******************************************************************************
  2  * Top contributors (to current version):
  3  *   Mudathir Mohamed, Mathias Preiner, Andres Noetzli
  4  *
  5  * This file is part of the cvc5 project.
  6  *
  7  * Copyright (c) 2009-2022 by the authors listed in the file AUTHORS
  8  * in the top-level source directory and their institutional affiliations.
  9  * All rights reserved.  See the file COPYING in the top-level source
 10  * directory for licensing information.
 11  * ****************************************************************************
 12  *
 13  * An example of solving floating-point problems with cvc5's cpp API
 14  *
 15  * This example shows to create floating-point types, variables and expressions,
 16  * and how to create rounding mode constants by solving toy problems. The
 17  * example also shows making special values (such as NaN and +oo) and converting
 18  * an IEEE 754-2008 bit-vector to a floating-point number.
 19  */
 20 
 21 #include <cvc5/cvc5.h>
 22 
 23 #include <iostream>
 24 #include <cassert>
 25 
 26 using namespace std;
 27 using namespace cvc5;
 28 
 29 int main()
 30 {
 31   Solver solver;
 32   solver.setOption("produce-models", "true");
 33 
 34   // Make single precision floating-point variables
 35   Sort fpt32 = solver.mkFloatingPointSort(8, 24);
 36   Term a = solver.mkConst(fpt32, "a");
 37   Term b = solver.mkConst(fpt32, "b");
 38   Term c = solver.mkConst(fpt32, "c");
 39   Term d = solver.mkConst(fpt32, "d");
 40   Term e = solver.mkConst(fpt32, "e");
 41 
 42   // Assert that floating-point addition is not associative:
 43   // (a + (b + c)) != ((a + b) + c)
 44   Term rm = solver.mkRoundingMode(ROUND_NEAREST_TIES_TO_EVEN);
 45   Term lhs = solver.mkTerm(
 46       FLOATINGPOINT_ADD, {rm, a, solver.mkTerm(FLOATINGPOINT_ADD, {rm, b, c})});
 47   Term rhs = solver.mkTerm(
 48       FLOATINGPOINT_ADD, {rm, solver.mkTerm(FLOATINGPOINT_ADD, {rm, a, b}), c});
 49   solver.assertFormula(solver.mkTerm(NOT, {solver.mkTerm(EQUAL, {a, b})}));
 50 
 51   Result r = solver.checkSat();  // result is sat
 52   assert (r.isSat());
 53 
 54   cout << "a = " << solver.getValue(a) << endl;
 55   cout << "b = " << solver.getValue(b) << endl;
 56   cout << "c = " << solver.getValue(c) << endl;
 57 
 58   // Now, let's restrict `a` to be either NaN or positive infinity
 59   Term nan = solver.mkFloatingPointNaN(8, 24);
 60   Term inf = solver.mkFloatingPointPosInf(8, 24);
 61   solver.assertFormula(solver.mkTerm(
 62       OR, {solver.mkTerm(EQUAL, {a, inf}), solver.mkTerm(EQUAL, {a, nan})}));
 63 
 64   r = solver.checkSat();  // result is sat
 65   assert (r.isSat());
 66 
 67   cout << "a = " << solver.getValue(a) << endl;
 68   cout << "b = " << solver.getValue(b) << endl;
 69   cout << "c = " << solver.getValue(c) << endl;
 70 
 71   // And now for something completely different. Let's try to find a (normal)
 72   // floating-point number that rounds to different integer values for
 73   // different rounding modes.
 74   Term rtp = solver.mkRoundingMode(ROUND_TOWARD_POSITIVE);
 75   Term rtn = solver.mkRoundingMode(ROUND_TOWARD_NEGATIVE);
 76   Op op = solver.mkOp(FLOATINGPOINT_TO_SBV, {16});  // (_ fp.to_sbv 16)
 77   lhs = solver.mkTerm(op, {rtp, d});
 78   rhs = solver.mkTerm(op, {rtn, d});
 79   solver.assertFormula(solver.mkTerm(FLOATINGPOINT_IS_NORMAL, {d}));
 80   solver.assertFormula(solver.mkTerm(NOT, {solver.mkTerm(EQUAL, {lhs, rhs})}));
 81 
 82   r = solver.checkSat();  // result is sat
 83   assert (r.isSat());
 84 
 85   // Convert the result to a rational and print it
 86   Term val = solver.getValue(d);
 87   Term realVal = solver.getValue(solver.mkTerm(FLOATINGPOINT_TO_REAL, {val}));
 88   cout << "d = " << val << " = " << realVal << endl;
 89   cout << "((_ fp.to_sbv 16) RTP d) = " << solver.getValue(lhs) << endl;
 90   cout << "((_ fp.to_sbv 16) RTN d) = " << solver.getValue(rhs) << endl;
 91 
 92   // For our final trick, let's try to find a floating-point number between
 93   // positive zero and the smallest positive floating-point number
 94   Term zero = solver.mkFloatingPointPosZero(8, 24);
 95   Term smallest = solver.mkFloatingPoint(8, 24, solver.mkBitVector(32, 0b001));
 96   solver.assertFormula(
 97       solver.mkTerm(AND,
 98                     {solver.mkTerm(FLOATINGPOINT_LT, {zero, e}),
 99                      solver.mkTerm(FLOATINGPOINT_LT, {e, smallest})}));
100 
101   r = solver.checkSat();  // result is unsat
102   assert (!r.isSat());
103 }