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
 26using namespace std;
 27using namespace cvc5;
 28
 29int 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}