mirror of https://github.com/CGAL/cgal
1152 lines
32 KiB
C++
1152 lines
32 KiB
C++
/****************************************************************************
|
|
* Core Library Version 1.7, August 2004
|
|
* Copyright (c) 1995-2004 Exact Computation Project
|
|
* All rights reserved.
|
|
*
|
|
* This file is part of CORE (http://cs.nyu.edu/exact/core/); you may
|
|
* redistribute it under the terms of the Q Public License version 1.0.
|
|
* See the file LICENSE.QPL distributed with CORE.
|
|
*
|
|
* Licensees holding a valid commercial license may use this file in
|
|
* accordance with the commercial license agreement provided with the
|
|
* software.
|
|
*
|
|
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
*
|
|
* File: Expr.cpp
|
|
*
|
|
* Written by
|
|
* Koji Ouchi <ouchi@simulation.nyu.edu>
|
|
* Chee Yap <yap@cs.nyu.edu>
|
|
* Igor Pechtchanski <pechtcha@cs.nyu.edu>
|
|
* Vijay Karamcheti <vijayk@cs.nyu.edu>
|
|
* Chen Li <chenli@cs.nyu.edu>
|
|
* Zilin Du <zilin@cs.nyu.edu>
|
|
* Sylvain Pion <pion@cs.nyu.edu>
|
|
*
|
|
* WWW URL: http://cs.nyu.edu/exact/
|
|
* Email: exact@cs.nyu.edu
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
***************************************************************************/
|
|
|
|
#include <CGAL/CORE/Expr.h>
|
|
#include <cmath>
|
|
|
|
CORE_BEGIN_NAMESPACE
|
|
|
|
#ifdef CORE_DEBUG_BOUND
|
|
unsigned int BFMSS_counter = 0;
|
|
unsigned int BFMSS_only_counter = 0;
|
|
unsigned int Measure_counter = 0;
|
|
unsigned int Measure_only_counter = 0;
|
|
unsigned int Cauchy_counter = 0;
|
|
unsigned int Cauchy_only_counter = 0;
|
|
unsigned int LiYap_counter = 0;
|
|
unsigned int LiYap_only_counter = 0;
|
|
unsigned int rootBoundHitCounter = 0;
|
|
unsigned int computeBoundCallsCounter = 0;
|
|
#endif
|
|
|
|
const char* Add::name = "+";
|
|
const char* Sub::name = "-";
|
|
|
|
/********************************************************
|
|
* class Expr
|
|
********************************************************/
|
|
const Expr& Expr::getZero() {
|
|
static Expr Zero(0);
|
|
return Zero;
|
|
}
|
|
const Expr& Expr::getOne() {
|
|
static Expr One(1);
|
|
return One;
|
|
}
|
|
|
|
// computes an interval comprising a pair of doubles
|
|
// Note:
|
|
//
|
|
// This function returns are two consecutive representable binary
|
|
// IEEE double values whichs contain the real value, but when you print out
|
|
// them, you might be confused by the decimal represention due to round.
|
|
//
|
|
void Expr::doubleInterval(double & lb, double & ub) const {
|
|
double d = doubleValue();
|
|
if (!finite(d)) { // if overflow, underflow or NaN
|
|
lb = ub = d;
|
|
return;
|
|
}
|
|
int sign = ((* this) -Expr(d)).sign();
|
|
// Seems like doubleValue() always give a lower bound,
|
|
// so sign = 0 or 1 (never -1).
|
|
//std::cout << "Sign = " << sign << std::endl;
|
|
if (sign == 0) {
|
|
lb = ub = d;
|
|
return;
|
|
}
|
|
int exp;
|
|
frexp(d, & exp); // get the exponent of d
|
|
exp--; // the exp from frexp satisfies
|
|
// 2^{exp-1} <= d < 2^{exp}
|
|
// But, we want exp to satisfy
|
|
// 2^{exp} <= d < 2^{exp+1}
|
|
if (sign > 0) {
|
|
lb = d;
|
|
ub = d + ldexp(1.0, -52+exp);
|
|
return;
|
|
} else {
|
|
ub = d;
|
|
lb = d - ldexp(1.0, -52+exp);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// floor(e, sub) returns the floor(e), and puts the
|
|
// remainder into sub.
|
|
BigInt floor(const Expr& e, Expr &sub) {
|
|
if (e==0) {
|
|
return 0;
|
|
}
|
|
BigInt f = e.approx(CORE_INFTY, 2).BigIntValue();
|
|
sub = e-f;
|
|
// Adjustment
|
|
if (sub<0)
|
|
++sub, --f;
|
|
if (sub>=1)
|
|
--sub, ++f;
|
|
assert(sub >=0 && sub<1); // got an assertion error? (Chee 3/24/04)
|
|
return f;
|
|
}
|
|
|
|
// Chenli: implemented algorithm from Goldberg's article.
|
|
// 7/01: Thanks to Serge Pashkov for fixing infinite loop when n=0.
|
|
Expr pow(const Expr& e, unsigned long n) {
|
|
if (n == 0)
|
|
return Expr(1);
|
|
else if (n == 1)
|
|
return e;
|
|
else {
|
|
Expr x = e;
|
|
while ((n % 2) == 0) { // n is even
|
|
x *= x;
|
|
n >>= 1;
|
|
}
|
|
Expr u = x;
|
|
while (true) {
|
|
n >>= 1;
|
|
if (n == 0)
|
|
return u;
|
|
x *= x;
|
|
if ((n % 2) == 1) // n is odd
|
|
u *= x;
|
|
}
|
|
//return u; // unreachable
|
|
}
|
|
}//pow
|
|
|
|
NodeInfo::NodeInfo() : appValue(CORE_REAL_ZERO), appComputed(false),
|
|
flagsComputed(false), knownPrecision(CORE_negInfty),
|
|
#ifdef CORE_DEBUG
|
|
relPrecision(EXTLONG_ZERO), absPrecision(CORE_negInfty), numNodes(0),
|
|
#endif
|
|
// Most of the following data members don't need to be
|
|
// initialized here.
|
|
d_e(EXTLONG_ZERO), visited(false), sign(0),
|
|
uMSB(CORE_negInfty), lMSB(CORE_negInfty),
|
|
// length(0),
|
|
measure(EXTLONG_ZERO), high(EXTLONG_ZERO), low(EXTLONG_ONE),
|
|
lc(EXTLONG_ZERO), tc(EXTLONG_ZERO),
|
|
v2p(EXTLONG_ZERO), v2m(EXTLONG_ZERO),
|
|
v5p(EXTLONG_ZERO), v5m(EXTLONG_ZERO),
|
|
u25(EXTLONG_ZERO), l25(EXTLONG_ZERO),
|
|
ratFlag(0), ratValue(NULL) { }
|
|
|
|
/********************************************************
|
|
* class ExprRep
|
|
********************************************************/
|
|
// constructor
|
|
ExprRep::ExprRep() : refCount(1), nodeInfo(NULL), ffVal(0.0) { }
|
|
|
|
// Computes the root bit bound of the expression.
|
|
// In effect, computeBound() returns the current value of low.
|
|
extLong ExprRep::computeBound() {
|
|
extLong measureBd = measure();
|
|
// extLong cauchyBd = length();
|
|
extLong ourBd = (d_e() - EXTLONG_ONE) * high() + lc();
|
|
// BFMSS[2,5] bound.
|
|
extLong bfmsskBd;
|
|
if (v2p().isInfty() || v2m().isInfty())
|
|
bfmsskBd = CORE_INFTY;
|
|
else
|
|
bfmsskBd = l25() + u25() * (d_e() - EXTLONG_ONE) - v2() - ceilLg5(v5());
|
|
|
|
// since we might compute \infty - \infty for this bound
|
|
if (bfmsskBd.isNaN())
|
|
bfmsskBd = CORE_INFTY;
|
|
|
|
extLong bd = core_min(measureBd,
|
|
// core_min(cauchyBd,
|
|
core_min(bfmsskBd, ourBd));
|
|
#ifdef CORE_SHOW_BOUNDS
|
|
std::cout << "Bounds (" << measureBd <<
|
|
"," << bfmsskBd << ", " << ourBd << "), ";
|
|
std::cout << "MIN = " << bd << std::endl;
|
|
std::cout << "d_e= " << d_e() << std::endl;
|
|
#endif
|
|
|
|
#ifdef CORE_DEBUG_BOUND
|
|
// Some statistics about which one is/are the winner[s].
|
|
computeBoundCallsCounter++;
|
|
int number_of_winners = 0;
|
|
std::cerr << " New contest " << std::endl;
|
|
if (bd == bfmsskBd) {
|
|
BFMSS_counter++;
|
|
number_of_winners++;
|
|
std::cerr << " BFMSS is the winner " << std::endl;
|
|
}
|
|
if (bd == measureBd) {
|
|
Measure_counter++;
|
|
number_of_winners++;
|
|
std::cerr << " measureBd is the winner " << std::endl;
|
|
}
|
|
/* if (bd == cauchyBd) {
|
|
Cauchy_counter++;
|
|
number_of_winners++;
|
|
std::cerr << " cauchyBd is the winner " << std::endl;
|
|
}
|
|
*/
|
|
if (bd == ourBd) {
|
|
LiYap_counter++;
|
|
number_of_winners++;
|
|
std::cerr << " ourBd is the winner " << std::endl;
|
|
}
|
|
|
|
assert(number_of_winners >= 1);
|
|
|
|
if (number_of_winners == 1) {
|
|
if (bd == bfmsskBd) {
|
|
BFMSS_only_counter++;
|
|
std::cerr << " BFMSSBd is the only winner " << std::endl;
|
|
} else if (bd == measureBd) {
|
|
Measure_only_counter++;
|
|
std::cerr << " measureBd is the only winner " << std::endl;
|
|
}
|
|
/* else if (bd == cauchyBd) {
|
|
Cauchy_only_counter++;
|
|
std::cerr << " cauchyBd is the only winner " << std::endl;
|
|
} */
|
|
else if (bd == ourBd) {
|
|
LiYap_only_counter++;
|
|
std::cerr << " ourBd is the only winner " << std::endl;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return bd;
|
|
}//computeBound()
|
|
|
|
void ExprRep::reduceToBigRat(const BigRat& rat) {
|
|
Real value(rat);
|
|
|
|
//appValue() = value;
|
|
appComputed() = false; // since appValue is not assigned until approx() is called
|
|
flagsComputed() = true;
|
|
knownPrecision() = CORE_negInfty;
|
|
|
|
#ifdef CORE_DEBUG
|
|
relPrecision() = EXTLONG_ZERO;
|
|
absPrecision() = CORE_negInfty;
|
|
//numNodes() = numNodes();
|
|
#endif
|
|
|
|
d_e() = EXTLONG_ONE;
|
|
//visited() = e->visited();
|
|
sign() = value.sign();
|
|
uMSB() = value.MSB();
|
|
lMSB() = value.MSB();
|
|
// length() = value.length(); // fixed? original = 1
|
|
measure() = value.height(); // measure <= height for rational value
|
|
|
|
// BFMSS[2,5] bound.
|
|
value.ULV_E(u25(), l25(), v2p(), v2m(), v5p(), v5m());
|
|
|
|
extLong u_e = u25() + v2p();
|
|
extLong l_e = l25() + v2m();
|
|
|
|
u_e = u_e + ceilLg5(v5p());
|
|
l_e = l_e + ceilLg5(v5m());
|
|
|
|
if (l_e == EXTLONG_ZERO) { // no divisions introduced
|
|
high() = u_e;
|
|
low() = EXTLONG_ONE - u_e; // - (u_e - 1)
|
|
} else {
|
|
high() = u_e - l_e + EXTLONG_ONE;
|
|
low() = 2 - high();
|
|
}
|
|
|
|
lc() = l_e;
|
|
tc() = u_e;
|
|
|
|
if (ratValue() == NULL)
|
|
ratValue() = new BigRat(rat);
|
|
else
|
|
*(ratValue()) = rat;
|
|
}
|
|
|
|
// This only copies the current information of the argument e to
|
|
// *this ExprRep.
|
|
void ExprRep::reduceTo(const ExprRep *e) {
|
|
if (e->appComputed()) {
|
|
appValue() = e->appValue();
|
|
appComputed() = true;
|
|
flagsComputed() = true;
|
|
knownPrecision() = e->knownPrecision();
|
|
#ifdef CORE_DEBUG
|
|
relPrecision() = e->relPrecision();
|
|
absPrecision() = e->absPrecision();
|
|
numNodes() = e->numNodes();
|
|
#endif
|
|
|
|
}
|
|
d_e() = e->d_e();
|
|
//visited() = e->visited();
|
|
sign() = e->sign();
|
|
uMSB() = e->uMSB();
|
|
lMSB() = e->lMSB();
|
|
// length() = e->length(); // fixed? original = 1
|
|
measure() = e->measure();
|
|
|
|
// BFMSS[2,5] bound.
|
|
u25() = e->u25();
|
|
l25() = e->l25();
|
|
v2p() = e->v2p();
|
|
v2m() = e->v2m();
|
|
v5p() = e->v5p();
|
|
v5m() = e->v5m();
|
|
|
|
high() = e->high();
|
|
low() = e->low(); // fixed? original = 0
|
|
lc() = e->lc();
|
|
tc() = e->tc();
|
|
|
|
// Chee (Mar 23, 2004), Notes on ratFlag():
|
|
// ===============================================================
|
|
// For more information on the use of this flag, see progs/pentagon.
|
|
// This is an integer valued member of the NodeInfo class.
|
|
// Its value is used to determine whether
|
|
// we can ``reduce'' an Expression to a single node containing
|
|
// a BigRat value. This reduction is done if the global variable
|
|
// rationalReduceFlag=true. The default value is false.
|
|
// This is the intepretation of ratFlag:
|
|
// ratFlag < 0 means irrational
|
|
// ratFlag = 0 means not initialized
|
|
// ratFlag > 0 means rational
|
|
// Currently, ratFlag>0 is an upper bound on the size of the expression,
|
|
// since we recursively compute
|
|
// ratFlag(v) = ratFlag(v.lchild)+ratFlag(v.rchild) + 1.
|
|
// PROPOSAL: if ratFlag() > RAT_REDUCE_THRESHHOLD
|
|
// then we automatically do a reduction. We must determine
|
|
// an empirical value for RAT_REDUCE_THRESHOLD
|
|
|
|
if (rationalReduceFlag) {
|
|
ratFlag() = e->ratFlag();
|
|
|
|
if (e->ratFlag() > 0 && e->ratValue() != NULL) {
|
|
ratFlag() ++;
|
|
if (ratValue() == NULL)
|
|
ratValue() = new BigRat(*(e->ratValue()));
|
|
else
|
|
*(ratValue()) = *(e->ratValue());
|
|
} else
|
|
ratFlag() = -1;
|
|
}
|
|
}
|
|
|
|
void ExprRep::reduceToZero() {
|
|
appValue() = CORE_REAL_ZERO;
|
|
appComputed() = true;
|
|
flagsComputed() = true;
|
|
knownPrecision() = CORE_negInfty;
|
|
#ifdef CORE_DEBUG
|
|
relPrecision() = EXTLONG_ZERO;
|
|
absPrecision() = CORE_negInfty;
|
|
// numNodes() = 0;
|
|
#endif
|
|
|
|
d_e() = EXTLONG_ONE;
|
|
visited() = false;
|
|
sign() = 0;
|
|
uMSB() = CORE_negInfty;
|
|
lMSB() = CORE_negInfty;
|
|
// length() = 0; // fixed? original = 1
|
|
measure() = EXTLONG_ZERO;
|
|
|
|
// BFMSS[2,5] bound.
|
|
u25() = l25() = v2p() = v2m() = v5p() = v5m() = EXTLONG_ZERO;
|
|
|
|
low() = EXTLONG_ONE; // fixed? original = 0
|
|
high() = lc() = tc() = EXTLONG_ZERO;
|
|
|
|
if (rationalReduceFlag) {
|
|
if (ratFlag() > 0) {
|
|
ratFlag() ++;
|
|
if (ratValue() == NULL)
|
|
ratValue() = new BigRat(0);
|
|
else
|
|
*(ratValue()) = 0;
|
|
} else
|
|
ratFlag() = 1;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Test whether the current approximate value satisfies
|
|
// the composite precision requirements [relPrec, absPrec].
|
|
////////////////////////////////////////////////////////////
|
|
|
|
bool ExprRep::withinKnownPrecision(const extLong& relPrec,
|
|
const extLong& absPrec) {
|
|
if (appComputed()) { // an approximate value has been evaluated.
|
|
if (appValue().isExact()) {
|
|
return true;
|
|
} else { // approximation has certain error.
|
|
// decide to which position it is required to compute correctly.
|
|
extLong required = core_max(-absPrec, appValue().lMSB()-relPrec);
|
|
// see whether the existing error is smaller than the requirement.
|
|
return (knownPrecision() <= required);
|
|
}
|
|
} else
|
|
return false;
|
|
}//withinKnownPrecision(a, r)
|
|
|
|
// approximate the expression to certain precisions when
|
|
// necessary (either no approximate value available or
|
|
// the existing one is not accurate enough).
|
|
void ExprRep::approx(const extLong& relPrec = defRelPrec,
|
|
const extLong& absPrec = defAbsPrec) {
|
|
if (!getSign())
|
|
return; // if it is exactly zero...
|
|
|
|
// NOTE: The Filter might give a precise enough approximation already.
|
|
if (!getExactSign())
|
|
return;
|
|
|
|
if (!appComputed() || (!withinKnownPrecision(relPrec, absPrec))) {
|
|
// it's necessary to re-evaluate.
|
|
// to avoid huge lMSB which would cause long time and problems.
|
|
|
|
// if it is a rational node
|
|
if (rationalReduceFlag && ratFlag() > 0 && ratValue() != NULL)
|
|
appValue() = Real(*(ratValue())).approx(relPrec, absPrec); //< shouldn't
|
|
// this case be done by computeApproxValue()?
|
|
else
|
|
computeApproxValue(relPrec, absPrec);
|
|
|
|
// update flags
|
|
appComputed() = true;
|
|
knownPrecision() = appValue().clLgErr();
|
|
#ifdef CORE_DEBUG
|
|
if (relPrecision() < relPrec)
|
|
relPrecision() = relPrec;
|
|
if (absPrecision() < absPrec)
|
|
absPrecision() = absPrec;
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
// return an approximate value to certain precision.
|
|
const Real& ExprRep::getAppValue(const extLong& relPrec,
|
|
const extLong& absPrec) {
|
|
if (getSign()) {
|
|
approx(relPrec, absPrec);
|
|
return appValue();
|
|
} else
|
|
return CORE_REAL_ZERO;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& o, ExprRep& rep) {
|
|
if (rep.getSign()) {
|
|
rep.approx(defRelPrec, defAbsPrec);
|
|
o << rep.appValue();
|
|
} else {
|
|
o << "0";
|
|
}
|
|
return o;
|
|
}
|
|
|
|
// Chee, Zilin: July 17, 2002
|
|
// Original algorithm is wrongly implemented, and can take time
|
|
// exponential in the size of the dag.
|
|
//
|
|
// METHOD:
|
|
// Inductively assume that all "visited" flags are false.
|
|
// This calls for a reimplementation of "count()" and "clearFlag()".
|
|
// Actually, we did not have to fix the count() function.
|
|
//
|
|
// (1) First recursively compute d_e for each node
|
|
// by calling the count() function.
|
|
// Important thing is count() will turn the "visited" flags
|
|
// to be true, so that there is no double counting.
|
|
// Furthermore, if d_e had already been computed, the
|
|
// arithmetic for d_e can be avoided (in this case,
|
|
// it is only the setting of "visited" flag that we
|
|
// are interested in!
|
|
// (2) At the end of count(), we have set all reachable nodes
|
|
// to "visited", and their d_e have been computed.
|
|
// (3) Now, call clearFlag() to recursively clear all reachable
|
|
// nodes. NOTE THAT PREVIOUSLY, clearFlag() was called
|
|
// first! This obvious is wrong
|
|
|
|
extLong ExprRep::degreeBound() {
|
|
if (d_e() == EXTLONG_ONE) // no radical nodes below
|
|
return EXTLONG_ONE;
|
|
count();
|
|
clearFlag();
|
|
return d_e();
|
|
}
|
|
// class ConstRealRep
|
|
// constructor
|
|
ConstRealRep::ConstRealRep(const Real & r) : value(r) {
|
|
if (!value.isExact()) {
|
|
// clone the BigFloat and set its error to zero.
|
|
value = value.BigFloatValue().makeExact();
|
|
}
|
|
ffVal = filteredFp(value);
|
|
}
|
|
|
|
// initialize nodeInfo
|
|
void ConstRep::initNodeInfo() {
|
|
nodeInfo = new NodeInfo();
|
|
d_e() = EXTLONG_ONE;
|
|
}
|
|
void UnaryOpRep::initNodeInfo() {
|
|
if (child->nodeInfo == NULL)
|
|
child->initNodeInfo();
|
|
nodeInfo = new NodeInfo();
|
|
}
|
|
void BinOpRep::initNodeInfo() {
|
|
if (first->nodeInfo == NULL)
|
|
first->initNodeInfo();
|
|
if (second->nodeInfo == NULL)
|
|
second->initNodeInfo();
|
|
nodeInfo = new NodeInfo();
|
|
}
|
|
|
|
#ifdef CORE_DEBUG
|
|
unsigned long ConstRep::dagSize() {
|
|
if (!visited()) {
|
|
visited() = true;
|
|
numNodes() = 1;
|
|
} else
|
|
numNodes() = 0;
|
|
return numNodes();
|
|
}
|
|
|
|
unsigned long UnaryOpRep::dagSize() {
|
|
if (!visited()) {
|
|
visited() = true;
|
|
numNodes() = child->dagSize() + 1;
|
|
} else
|
|
numNodes() = 0;
|
|
return numNodes();
|
|
}
|
|
|
|
unsigned long BinOpRep::dagSize() {
|
|
if (!visited()) {
|
|
visited() = true;
|
|
numNodes() = first->dagSize() + second->dagSize() + 1;
|
|
} else
|
|
numNodes() = 0;
|
|
return numNodes();
|
|
}
|
|
|
|
void ConstRep::fullClearFlag() {
|
|
if (visited())
|
|
visited() = false;
|
|
}
|
|
|
|
void UnaryOpRep::fullClearFlag() {
|
|
if (visited()) {
|
|
child->fullClearFlag();
|
|
visited() = false;
|
|
}
|
|
}
|
|
|
|
void BinOpRep::fullClearFlag() {
|
|
if (visited()) {
|
|
first->fullClearFlag();
|
|
second->fullClearFlag();
|
|
visited() = false;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// clear visited flag
|
|
//
|
|
/* see Expr.h
|
|
void ConstRep::clearFlag()
|
|
{ visited = false; }
|
|
*/
|
|
void UnaryOpRep::clearFlag() {
|
|
if (d_e() == EXTLONG_ONE)
|
|
return; // no radicals below.
|
|
if (visited()) {
|
|
visited() = false;
|
|
child->clearFlag();
|
|
}
|
|
}
|
|
// class BinOpRep
|
|
void BinOpRep::clearFlag() {
|
|
if (d_e() == EXTLONG_ONE)
|
|
return; // rational below
|
|
if (visited()) {
|
|
visited() = false;
|
|
first->clearFlag();
|
|
second->clearFlag();
|
|
}
|
|
}
|
|
|
|
//
|
|
// count # of squareroot
|
|
//
|
|
extLong ConstRep::count() {
|
|
if (visited())
|
|
return EXTLONG_ONE;
|
|
visited() = true;
|
|
return d_e();
|
|
}
|
|
|
|
extLong NegRep::count() {
|
|
if (d_e() == EXTLONG_ONE)
|
|
return EXTLONG_ONE;
|
|
if (visited())
|
|
return EXTLONG_ONE;
|
|
visited() = true;
|
|
d_e() = child->count();
|
|
return d_e();
|
|
}
|
|
|
|
extLong SqrtRep::count() {
|
|
if (d_e() == EXTLONG_ONE)
|
|
return EXTLONG_ONE;
|
|
if (visited())
|
|
return EXTLONG_ONE;
|
|
visited() = true;
|
|
d_e() = child->count() * EXTLONG_TWO;
|
|
return d_e();
|
|
}
|
|
|
|
extLong BinOpRep::count() {
|
|
if (d_e() == EXTLONG_ONE)
|
|
return EXTLONG_ONE;
|
|
if (visited())
|
|
return EXTLONG_ONE;
|
|
visited() = true;
|
|
d_e() = first->count() * second->count();
|
|
return d_e();
|
|
}
|
|
|
|
//
|
|
// compute exact flags functions
|
|
//
|
|
// exact value
|
|
|
|
void computeExactFlags_temp(ConstRep* t, const Real &value) {
|
|
// Chen Li: the following is incorrect:
|
|
// uMSB = lMSB = value.MSB();
|
|
// because the value could be a BigFloat which is an interval.
|
|
if (value.isExact()) {
|
|
t->uMSB() = t->lMSB() = value.MSB();
|
|
} else {
|
|
t->uMSB() = value.uMSB();
|
|
t->lMSB() = value.lMSB();
|
|
core_error("Leaves in DAG is not exact!", __FILE__, __LINE__, true);
|
|
}
|
|
|
|
t->sign() = value.sign();
|
|
// t->length() = value.length();
|
|
t->measure() = value.height(); // for rationals and integers,
|
|
// measure = height.
|
|
|
|
// BFMSS[2,5] bound.
|
|
value.ULV_E(t->u25(), t->l25(), t->v2p(), t->v2m(), t->v5p(), t->v5m());
|
|
|
|
// The original BFMSS parameters can be set from the BFMSS[2,5] parameters.
|
|
// Here we just need them locally.
|
|
extLong u_e = t->u25() + t->v2p() + ceilLg5(t->v5p());
|
|
extLong l_e = t->l25() + t->v2m() + ceilLg5(t->v5m());
|
|
|
|
#ifdef ORIGINAL_BFMSS
|
|
// To go back to the original BFMSS :
|
|
t->u25() = u_e;
|
|
t->l25() = l_e;
|
|
t->v2p() = t->v2m() = t->v5p() = t->v5m() = EXTLONG_ZERO;
|
|
#elif defined BFMSS_2_ONLY
|
|
// To go back to BFMSS[2] only :
|
|
t->u25() = t->u25() + ceilLg5(t->v5p());
|
|
t->l25() = t->l25() + ceilLg5(t->v5m());
|
|
t->v5p() = t->v5m() = EXTLONG_ZERO;
|
|
#endif
|
|
|
|
if (l_e == EXTLONG_ZERO) { // no divisions introduced
|
|
t->high() = u_e;
|
|
t->low() = EXTLONG_ONE - u_e; // - (u_e - 1)
|
|
} else {
|
|
t->high() = u_e - l_e + EXTLONG_ONE;
|
|
t->low() = EXTLONG_TWO - t->high();
|
|
}
|
|
|
|
t->lc() = l_e;
|
|
t->tc() = u_e;
|
|
|
|
// set BigRat value
|
|
if (rationalReduceFlag) {
|
|
t->ratFlag() = 1;
|
|
t->ratValue() = new BigRat(value.BigRatValue());
|
|
}
|
|
|
|
t->flagsComputed() = true;
|
|
}
|
|
|
|
void ConstDoubleRep::computeExactFlags() {// can be made more efficient
|
|
computeExactFlags_temp(this, Real(ffVal.getValue()));
|
|
}
|
|
|
|
void ConstRealRep::computeExactFlags() {
|
|
computeExactFlags_temp(this, value);
|
|
}
|
|
|
|
void NegRep::computeExactFlags() {
|
|
if (!child->flagsComputed())
|
|
child->computeExactFlags();
|
|
|
|
if (child->sign() == 0) {
|
|
reduceToZero();
|
|
return;
|
|
}
|
|
|
|
if (rationalReduceFlag) {
|
|
if (child->ratFlag()>0 && child->ratValue() != NULL) {
|
|
BigRat val = -(*(child->ratValue()));
|
|
reduceToBigRat(val);
|
|
ratFlag() = child->ratFlag()+1;
|
|
return;
|
|
} else
|
|
ratFlag() = -1;
|
|
}
|
|
|
|
sign() = -child->sign();
|
|
uMSB() = child->uMSB();
|
|
lMSB() = child->lMSB();
|
|
|
|
// length() = child->length();
|
|
measure() = child->measure();
|
|
u25() = child->u25();
|
|
l25() = child->l25();
|
|
v2p() = child->v2p();
|
|
v2m() = child->v2m();
|
|
v5p() = child->v5p();
|
|
v5m() = child->v5m();
|
|
high() = child->high();
|
|
low() = child->low();
|
|
lc() = child->lc();
|
|
tc() = child->tc();
|
|
flagsComputed() = true;
|
|
}//NegRep::computeExactFlags
|
|
|
|
void SqrtRep::computeExactFlags() {
|
|
if (!child->flagsComputed())
|
|
child->computeExactFlags();
|
|
|
|
if (rationalReduceFlag)
|
|
ratFlag() = -1;
|
|
|
|
sign() = child->sign();
|
|
if (sign() < 0)
|
|
core_error("squareroot is called with negative operand.",
|
|
__FILE__, __LINE__, true);
|
|
|
|
uMSB() = child->uMSB() / EXTLONG_TWO;
|
|
lMSB() = child->lMSB() / EXTLONG_TWO;
|
|
|
|
// length() = child->length();
|
|
measure() = child->measure();
|
|
|
|
// BFMSS[2,5] bound.
|
|
if (child->v2p() + ceilLg5(child->v5p()) + child->u25() >=
|
|
child->v2m() + ceilLg5(child->v5m()) + child->l25()) {
|
|
extLong vtilda2 = child->v2p() + child->v2m();
|
|
v2p() = vtilda2 / EXTLONG_TWO;
|
|
v2m() = child->v2m();
|
|
extLong vmod2;
|
|
if (v2p().isInfty())
|
|
vmod2 = CORE_INFTY;
|
|
else
|
|
vmod2 = vtilda2 - EXTLONG_TWO*v2p(); // == vtilda2 % 2
|
|
extLong vtilda5 = child->v5p() + child->v5m();
|
|
v5p() = vtilda5 / EXTLONG_TWO;
|
|
v5m() = child->v5m();
|
|
extLong vmod5;
|
|
if (v5p().isInfty())
|
|
vmod5 = CORE_INFTY;
|
|
else
|
|
vmod5 = vtilda5 - EXTLONG_TWO*v5p(); // == vtilda5 % 2
|
|
u25() = (child->u25() + child->l25() + vmod2 + ceilLg5(vmod5) + EXTLONG_ONE) / EXTLONG_TWO;
|
|
l25() = child->l25();
|
|
} else {
|
|
extLong vtilda2 = child->v2p() + child->v2m();
|
|
v2p() = child->v2p();
|
|
v2m() = vtilda2 / EXTLONG_TWO;
|
|
extLong vmod2;
|
|
if (v2m().isInfty())
|
|
vmod2 = CORE_INFTY;
|
|
else
|
|
vmod2 = vtilda2 - EXTLONG_TWO*v2m(); // == vtilda2 % 2
|
|
extLong vtilda5 = child->v5p() + child->v5m();
|
|
v5p() = child->v5p();
|
|
v5m() = vtilda5 / EXTLONG_TWO;
|
|
u25() = child->u25();
|
|
extLong vmod5;
|
|
if (v5m().isInfty())
|
|
vmod5 = CORE_INFTY;
|
|
else
|
|
vmod5 = vtilda5 - EXTLONG_TWO*v5m(); // == vtilda5 % 2
|
|
l25() = (child->u25() + child->l25() + vmod2 + ceilLg5(vmod5) + EXTLONG_ONE) / EXTLONG_TWO;
|
|
}
|
|
|
|
high() = (child->high() +EXTLONG_ONE)/EXTLONG_TWO;
|
|
low() = child->low() / EXTLONG_TWO;
|
|
lc() = child->lc();
|
|
tc() = child->tc();
|
|
flagsComputed() = true;
|
|
}// SqrtRep::computeExactFlags
|
|
|
|
void MultRep::computeExactFlags() {
|
|
if (!first->flagsComputed())
|
|
first->computeExactFlags();
|
|
if (!second->flagsComputed())
|
|
second->computeExactFlags();
|
|
|
|
if ((!first->sign()) || (!second->sign())) {
|
|
// value must be exactly zero.
|
|
reduceToZero();
|
|
return;
|
|
}
|
|
// rational node
|
|
if (rationalReduceFlag) {
|
|
if (first->ratFlag() > 0 && second->ratFlag() > 0) {
|
|
BigRat val = (*(first->ratValue()))*(*(second->ratValue()));
|
|
reduceToBigRat(val);
|
|
ratFlag() = first->ratFlag() + second->ratFlag();
|
|
return;
|
|
} else
|
|
ratFlag() = -1;
|
|
}
|
|
|
|
// value is irrational.
|
|
uMSB() = first->uMSB() + second->uMSB() + EXTLONG_ONE;
|
|
lMSB() = first->lMSB() + second->lMSB();
|
|
sign() = first->sign() * second->sign();
|
|
|
|
extLong df = first->d_e();
|
|
extLong ds = second->d_e();
|
|
// extLong lf = first->length();
|
|
// extLong ls = second->length();
|
|
|
|
// length() = df * ls + ds * lf;
|
|
measure() = (first->measure()) * ds+(second->measure()) * df;
|
|
|
|
// BFMSS[2,5] bound.
|
|
v2p() = first->v2p() + second->v2p();
|
|
v2m() = first->v2m() + second->v2m();
|
|
v5p() = first->v5p() + second->v5p();
|
|
v5m() = first->v5m() + second->v5m();
|
|
u25() = first->u25() + second->u25();
|
|
l25() = first->l25() + second->l25();
|
|
|
|
high() = first->high() + second->high();
|
|
low() = first->low() + second->low();
|
|
|
|
lc() = ds * first->lc() + df * second->lc();
|
|
tc() = core_min(ds * first->tc() + df * second->tc(), measure());
|
|
|
|
flagsComputed() = true;
|
|
}// MultRep::computeExactFlags
|
|
|
|
void DivRep::computeExactFlags() {
|
|
if (!first->flagsComputed())
|
|
first->computeExactFlags();
|
|
if (!second->flagsComputed())
|
|
second->computeExactFlags();
|
|
|
|
if (!second->sign())
|
|
core_error("zero divisor.", __FILE__, __LINE__, true);
|
|
|
|
if (!first->sign()) {// value must be exactly zero.
|
|
reduceToZero();
|
|
return;
|
|
}
|
|
|
|
// rational node
|
|
if (rationalReduceFlag) {
|
|
if (first->ratFlag() > 0 && second->ratFlag() > 0) {
|
|
BigRat val = (*(first->ratValue()))/(*(second->ratValue()));
|
|
reduceToBigRat(val);
|
|
ratFlag() = first->ratFlag() + second->ratFlag();
|
|
return;
|
|
} else
|
|
ratFlag() = -1;
|
|
}
|
|
|
|
// value is irrational.
|
|
uMSB() = first->uMSB() - second->lMSB();
|
|
lMSB() = first->lMSB() - second->uMSB() - EXTLONG_ONE;
|
|
sign() = first->sign() * second->sign();
|
|
|
|
extLong df = first->d_e();
|
|
extLong ds = second->d_e();
|
|
// extLong lf = first->length();
|
|
// extLong ls = second->length();
|
|
|
|
// length() = df * ls + ds * lf;
|
|
measure() = (first->measure())*ds + (second->measure())*df;
|
|
|
|
// BFMSS[2,5] bound.
|
|
v2p() = first->v2p() + second->v2m();
|
|
v2m() = first->v2m() + second->v2p();
|
|
v5p() = first->v5p() + second->v5m();
|
|
v5m() = first->v5m() + second->v5p();
|
|
u25() = first->u25() + second->l25();
|
|
l25() = first->l25() + second->u25();
|
|
|
|
high() = first->high() + second->low();
|
|
low() = first->low() + second->high();
|
|
|
|
lc() = ds * first->lc() + df * second->tc();
|
|
tc() = core_min(ds * first->tc() + df * second->lc(), measure());
|
|
|
|
flagsComputed() = true;
|
|
}
|
|
|
|
//
|
|
// approximation functions
|
|
//
|
|
void ConstDoubleRep::computeApproxValue(const extLong& /*relPrec*/,
|
|
const extLong& /*absPrec*/)
|
|
// can ignore precision bounds since ffVal.getValue() returns exact value
|
|
{
|
|
appValue() = Real(ffVal.getValue());
|
|
}
|
|
|
|
void ConstRealRep::computeApproxValue(const extLong& relPrec,
|
|
const extLong& absPrec) {
|
|
appValue() = value.approx(relPrec, absPrec);
|
|
}
|
|
|
|
void NegRep::computeApproxValue(const extLong& relPrec,
|
|
const extLong& absPrec) {
|
|
appValue() = -child->getAppValue(relPrec, absPrec);
|
|
}
|
|
|
|
void SqrtRep::computeApproxValue(const extLong& relPrec,
|
|
const extLong& absPrec) {
|
|
extLong r = relPrec + relPrec + EXTLONG_EIGHT; // chenli: ???
|
|
extLong a = absPrec + absPrec + EXTLONG_EIGHT;
|
|
extLong pr = - lMSB() + r;
|
|
extLong p = pr < a ? pr : a;
|
|
|
|
Real val = child->getAppValue(r, a);
|
|
if (incrementalEvalFlag) {
|
|
if (appValue() == CORE_REAL_ZERO)
|
|
appValue() = val;
|
|
appValue() = val.sqrt(p, appValue().BigFloatValue());
|
|
} else
|
|
appValue() = val.sqrt(p);
|
|
}
|
|
|
|
void MultRep::computeApproxValue(const extLong& relPrec,
|
|
const extLong& absPrec) {
|
|
if (lMSB() < EXTLONG_BIG && lMSB() > EXTLONG_SMALL) {
|
|
extLong r = relPrec + EXTLONG_FOUR;
|
|
extLong afr = - first->lMSB() + EXTLONG_ONE;
|
|
extLong afa = second->uMSB() + absPrec + EXTLONG_FIVE;
|
|
extLong af = afr > afa ? afr : afa;
|
|
extLong asr = - second->lMSB() + EXTLONG_ONE;
|
|
extLong asa = first->uMSB() + absPrec + EXTLONG_FIVE;
|
|
extLong as = asr > asa ? asr : asa;
|
|
appValue() = first->getAppValue(r, af)*second->getAppValue(r, as);
|
|
} else {
|
|
std::cerr << "lMSB = " << lMSB() << std::endl;
|
|
core_error("a huge lMSB in MulRep", __FILE__, __LINE__, false);
|
|
}
|
|
}
|
|
|
|
void DivRep::computeApproxValue(const extLong& relPrec,
|
|
const extLong& absPrec) {
|
|
if (lMSB() < EXTLONG_BIG && lMSB() > EXTLONG_SMALL) {
|
|
extLong rr = relPrec + EXTLONG_SEVEN; // These rules come from
|
|
extLong ra = uMSB() + absPrec + EXTLONG_EIGHT; // Koji's Master Thesis, page 65
|
|
extLong ra2 = core_max(ra, EXTLONG_TWO);
|
|
extLong r = core_min(rr, ra2);
|
|
extLong af = - first->lMSB() + r;
|
|
extLong as = - second->lMSB() + r;
|
|
|
|
extLong pr = relPrec + EXTLONG_SIX;
|
|
extLong pa = uMSB() + absPrec + EXTLONG_SEVEN;
|
|
extLong p = core_min(pr, pa); // Seems to be an error:
|
|
// p can be negative here!
|
|
// Also, this does not conform to
|
|
// Koji's thesis which has a default
|
|
// relative precision (p.65).
|
|
|
|
appValue() = first->getAppValue(r, af).div(second->getAppValue(r, as), p);
|
|
} else {
|
|
std::cerr << "lMSB = " << lMSB() << std::endl;
|
|
core_error("a huge lMSB in DivRep", __FILE__, __LINE__, false);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Debug Help Functions
|
|
//
|
|
void Expr::debug(int mode, int level, int depthLimit) const {
|
|
std::cout << "-------- Expr debug() -----------" << std::endl;
|
|
std::cout << "rep = " << rep << std::endl;
|
|
if (mode == Expr::LIST_MODE)
|
|
rep->debugList(level, depthLimit);
|
|
else if (mode == Expr::TREE_MODE)
|
|
rep->debugTree(level, 0, depthLimit);
|
|
else
|
|
core_error("unknown debugging mode", __FILE__, __LINE__, false);
|
|
std::cout << "---- End Expr debug(): " << std::endl;
|
|
}
|
|
|
|
|
|
const std::string ExprRep::dump(int level) const {
|
|
std::ostringstream ost;
|
|
if (level == OPERATOR_ONLY) {
|
|
ost << op();
|
|
} else if (level == VALUE_ONLY) {
|
|
ost << appValue();
|
|
} else if (level == OPERATOR_VALUE) {
|
|
ost << op() << "[val: " << appValue() << "]";
|
|
} else if (level == FULL_DUMP) {
|
|
ost << op()
|
|
<< "[val: " << appValue() << "; "
|
|
<< "kp: " << knownPrecision() << "; "
|
|
#ifdef CORE_DEBUG
|
|
<< "r: " << relPrecision() << "; "
|
|
<< "a: " << absPrecision() << "; "
|
|
#endif
|
|
<< "lMSB: " << lMSB() << "; "
|
|
<< "uMSB: " << uMSB() << "; "
|
|
<< "sign: " << sign() << "; "
|
|
// << "length: " << length() << "; "
|
|
<< "measure: " << measure() << "; "
|
|
<< "d_e: " << d_e() << "; "
|
|
<< "u25: " << u25() << "; "
|
|
<< "l25: " << l25() << "; "
|
|
<< "v2p: " << v2p() << "; "
|
|
<< "v2m: " << v2m() << "; "
|
|
<< "v5p: " << v5p() << "; "
|
|
<< "v5m: " << v5m() << "; "
|
|
<< "high: " << high() << "; "
|
|
<< "low: " << low() << "; "
|
|
<< "lc: " << lc() << "; "
|
|
<< "tc: " << tc()
|
|
<< "]";
|
|
}
|
|
return std::string(ost.str());
|
|
// note that str() return an array not properly terminated!
|
|
}
|
|
|
|
|
|
void UnaryOpRep::debugList(int level, int depthLimit) const {
|
|
if (depthLimit <= 0)
|
|
return;
|
|
if (level == Expr::SIMPLE_LEVEL) {
|
|
std::cout << "(" << dump(OPERATOR_VALUE);
|
|
child->debugList(level, depthLimit - 1);
|
|
std::cout << ")";
|
|
} else if (level == Expr::DETAIL_LEVEL) {
|
|
std::cout << "(" << dump(FULL_DUMP);
|
|
child->debugList(level, depthLimit - 1);
|
|
std::cout << ")";
|
|
}
|
|
}
|
|
|
|
void UnaryOpRep::debugTree(int level, int indent, int depthLimit) const {
|
|
if (depthLimit <= 0)
|
|
return;
|
|
for (int i = 0; i<indent; i++ )
|
|
std::cout << " ";
|
|
std::cout << "|_";
|
|
if (level == Expr::SIMPLE_LEVEL)
|
|
std::cout << dump(OPERATOR_VALUE);
|
|
else if (level == Expr::DETAIL_LEVEL)
|
|
std::cout << dump(FULL_DUMP);
|
|
std::cout << std::endl;
|
|
child->debugTree(level, indent + 2, depthLimit - 1);
|
|
}
|
|
|
|
void ConstRep::debugList(int level, int depthLimit) const {
|
|
if (depthLimit <= 0)
|
|
return;
|
|
if (level == Expr::SIMPLE_LEVEL) {
|
|
std::cout << "(" << dump(OPERATOR_VALUE) << ")";
|
|
} else if (level == Expr::DETAIL_LEVEL) {
|
|
std::cout << "(" << dump(FULL_DUMP) << ")";
|
|
}
|
|
}
|
|
|
|
void ConstRep::debugTree(int level, int indent, int depthLimit) const {
|
|
if (depthLimit <= 0)
|
|
return;
|
|
for (int i=0; i<indent; i++)
|
|
std::cout << " ";
|
|
std::cout << "|_";
|
|
if (level == Expr::SIMPLE_LEVEL)
|
|
std::cout << dump(OPERATOR_VALUE);
|
|
else if (level == Expr::DETAIL_LEVEL)
|
|
std::cout << dump(FULL_DUMP);
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
void BinOpRep::debugList(int level, int depthLimit) const {
|
|
if (depthLimit <= 0 )
|
|
return;
|
|
std::cout << "(";
|
|
if (level == Expr::SIMPLE_LEVEL) {
|
|
std::cout << dump(OPERATOR_VALUE);
|
|
} else if (level == Expr::DETAIL_LEVEL) {
|
|
std::cout << dump(FULL_DUMP);
|
|
}
|
|
first->debugList(level, depthLimit - 1);
|
|
std::cout << ", ";
|
|
second->debugList(level, depthLimit - 1);
|
|
std::cout << ")" ;
|
|
}
|
|
|
|
void BinOpRep::debugTree(int level, int indent, int depthLimit) const {
|
|
if (depthLimit <= 0)
|
|
return;
|
|
for (int i=0; i<indent; i++)
|
|
std::cout << " ";
|
|
std::cout << "|_";
|
|
if (level == Expr::SIMPLE_LEVEL) {
|
|
std::cout << dump(OPERATOR_VALUE);
|
|
} else if (level == Expr::DETAIL_LEVEL) {
|
|
std::cout << dump(FULL_DUMP);
|
|
}
|
|
std::cout << std::endl;
|
|
first->debugTree(level, indent + 2, depthLimit - 1);
|
|
second->debugTree(level, indent + 2, depthLimit - 1);
|
|
}
|
|
|
|
CORE_END_NAMESPACE
|