/* * gfanlib_circuittabletypeint.h * * Created on: Apr 10, 2016 * Author: anders */ #ifndef GFANLIB_CIRCUITTABLEINT_H_ #define GFANLIB_CIRCUITTABLEINT_H_ #include "../factory/globaldefs.h" #include #include #include #include namespace gfan{ class MVMachineIntegerOverflow: public std::exception { virtual const char* what() const throw() { return "Exception: Overflow (or possible future overflow) in 32/64 bit integers in tropical homotopy."; } }; typedef MVMachineIntegerOverflow MVMachineIntegerOverflowType; EXTERN_INST_VAR MVMachineIntegerOverflowType MVMachineIntegerOverflow; /* * The philosophy here is that if this class overflows, then the computation needs to be restarted. Therefore * all overflows must be caught. */ class CircuitTableInt32{ public: class Divisor{ public: int32_t v; int shift; int32_t multiplicativeInverse; Divisor(CircuitTableInt32 const &a)// for exact division { // A good place to read about these tricks seems to be the book "Hacker's Delight" by Warren. v=a.v; shift=0; int32_t t=v; // uint32_t t=v; assert(t); while(!(t&1)){t>>= 1;shift++;} uint32_t inverse=t; while(t*inverse!=1)inverse*=2-t*inverse; multiplicativeInverse=inverse; } }; class Double{ public: int64_t v; Double():v(0){}; Double(int64_t a):v(a){}; Double &operator+=(Double a){v+=a.v;return *this;} Double &operator-=(Double a){v-=a.v;return *this;} CircuitTableInt32 castToSingle()const; bool isZero()const{return v==0;} bool isNegative()const{return v<0;} Double operator-()const{Double ret;ret.v=-v;return ret;} friend Double operator-(Double const &a, Double const &b){return Double(a.v-b.v);} friend Double operator+(Double const &a, Double const &b){return Double(a.v+b.v);} Double &addWithOverflowCheck(Double const &a) { if(a.v<0 || v<0 || a.v>1000000000000000000 || v>1000000000000000000) throw MVMachineIntegerOverflow; v+=a.v; return *this; } std::string toString()const{std::stringstream s;s<-30000 && v<30000;}// Is it better to allow only non-negative numbers? static bool isSuitableSummationNumber(int numberOfSummands){return numberOfSummands<30000;} CircuitTableInt32(){v=0;}; CircuitTableInt32(CircuitTableInt32 const &m):v(m.v){} CircuitTableInt32(int32_t val):v(val){}; class CircuitTableInt32 &operator=(int32_t a){v=a;return *this;} CircuitTableInt32 operator-()const{CircuitTableInt32 ret;ret.v=-v;return ret;} CircuitTableInt32 &operator-=(CircuitTableInt32 a){v-=a.v;return *this;} CircuitTableInt32 &operator+=(CircuitTableInt32 a){v+=a.v;return *this;} CircuitTableInt32 &operator*=(CircuitTableInt32 a){v*=a.v;return *this;} friend bool operator<=(CircuitTableInt32 const &a, CircuitTableInt32 const &b){return a.v<=b.v;} friend bool operator==(CircuitTableInt32 const &a, CircuitTableInt32 const &b){return a.v==b.v;} bool isZero()const{return v==0;} bool isOne()const{return v==1;} bool isNonZero()const{return v!=0;} bool isNegative()const{return v<0;} bool isPositive()const{return v>0;} friend int determinantSign1(CircuitTableInt32 const &a, CircuitTableInt32 const &c, CircuitTableInt32 const &b, CircuitTableInt32 const &d)//NOTICE MIXED ORDER. MUST WORK BY EXTENDING { int64_t r=((int64_t)a.v)*((int64_t)c.v)-((int64_t)b.v)*((int64_t)d.v); if(r>0)return 1; if(r<0)return -1; return 0; } friend int determinantSign2(CircuitTableInt32::Double const &a, CircuitTableInt32 const &c, CircuitTableInt32::Double const &b, CircuitTableInt32 const &d)//NOTICE MIXED ORDER. MUST WORK BY EXTENDING { int64_t r1=(a.v)*((int64_t)c.v); int64_t r2=(b.v)*((int64_t)d.v); if(r1>r2)return 1; if(r1extend();t+=extendedMultiplication(a,b);*this=t.castToSingle();return *this;} CircuitTableInt32 &msubWithOverflowChecking(CircuitTableInt32 const &a, CircuitTableInt32 const&b){Double s=this->extend();s-=extendedMultiplication(a,b);*this=s.castToSingle();return *this;} CircuitTableInt32 &subWithOverflowChecking(CircuitTableInt32 const &a){Double t=this->extend();t-=a.extend();*this=t.castToSingle();return *this;} CircuitTableInt32 &addWithOverflowChecking(CircuitTableInt32 const &a){Double t=this->extend();t+=a.extend();*this=t.castToSingle();return *this;} CircuitTableInt32 negatedWithOverflowChecking()const{return (-extend()).castToSingle();} friend Double extendedMultiplication(CircuitTableInt32 const &a, CircuitTableInt32 const &b){Double ret;ret.v=((int64_t)a.v)*((int64_t)b.v);return ret;} friend Double extendedMultiplication(CircuitTableInt32 const &a, int32_t b){Double ret;ret.v=((int64_t)a.v)*((int64_t)b);return ret;}//to be removed? friend CircuitTableInt32 min(CircuitTableInt32 const &a, CircuitTableInt32 const &b){return (a.v>=b.v)?b:a;} friend CircuitTableInt32 max(CircuitTableInt32 const &a, CircuitTableInt32 const &b){return (a.v<=b.v)?b:a;} friend CircuitTableInt32 negabs(CircuitTableInt32 const &a){return min(a,-a);} friend CircuitTableInt32 dotDiv(CircuitTableInt32 const &s, CircuitTableInt32 const &a, CircuitTableInt32 const &t, CircuitTableInt32 const &b, CircuitTableInt32::Divisor const &q) { return CircuitTableInt32(((((int32_t)(((uint64_t)(((int64_t)s.v)*((int64_t)a.v)+((int64_t)t.v)*((int64_t)b.v)))>>q.shift)))*q.multiplicativeInverse)); } friend void dotDivAssign(CircuitTableInt32 &s, CircuitTableInt32 const &a, CircuitTableInt32 const &t, CircuitTableInt32 const &b, CircuitTableInt32::Divisor const &q)//as above but assigning to first argument. This helps the vectorizer. { s.v=((((int32_t)(((uint64_t)(((int64_t)s.v)*((int64_t)a.v)+((int64_t)t.v)*((int64_t)b.v)))>>q.shift)))*q.multiplicativeInverse); } static int MIN(int32_t a, int32_t b) { return (ab)?a:b; } static CircuitTableInt32 computeNegativeBound(CircuitTableInt32 * __restrict__ Ai, int w) { CircuitTableInt32 M=0; CircuitTableInt32 m=0; for(int j=0;j0){s.v>>=1;t.v>>=1;denominatorDivisor.shift--;denominatorDivisor.v>>=1;} CircuitTableInt32 max=0; CircuitTableInt32 min=0; // This is a bound on the absolute value of the sums of products before dividing by the denominator // The calculation can overflow, but since we are casting to unsigned long, this is not a problem. uint64_t positiveResultBoundTimesD=(negabs(t).v*((int64_t)boundA.v)+negabs(s).v*((int64_t)boundB.v)); /* The first case is the case where we know that the intermediate results fit in 32bit before shifting down. * In other words, the shifted-in bits of the results are equal. * In that case the intermediate result can be computed with 32bits. */ if(positiveResultBoundTimesD<((((int64_t)0x40000000)*denominatorDivisor.v)>>denominatorDivisor.shift))//check this carefully {//FAST VERSION // debug<>denominatorDivisor.shift; min.v=MIN(min.v,aa[i].v); max.v=MAX(max.v,aa[i].v); } if(-max<=min)min=-max; return min; } else { /* The next case would be to check if the result is known to fit in 32bit. * In that case intermediate results would be handled in 64 bit, * but the final result would not have to be checked for 32 bit overflows. */ if(positiveResultBoundTimesD<((((int64_t)0x40000000)*denominatorDivisor.v))) { for(int i=0;i>denominatorDivisor.shift)))*denominatorDivisor.multiplicativeInverse); if(max<=aa[i])max=aa[i]; if(aa[i]<=min)min=aa[i]; } if(-max<=min)min=-max; } /* The last case would be to where we don't know that the results will fit in 32 bit. * Since we need to compute max and min anyway, we can compute these quantities in 64bit * and just check if they fit in 32bit at the end. */ else { bool doesOverflow=(((uint32_t)t.v)==0x80000000); int64_t min64=0; int64_t max64=0; for(int i=0;i=0x7fffffff || -v>=0x7fffffff) throw MVMachineIntegerOverflow; return CircuitTableInt32(v); } } #endif /* GFANLIB_CIRCUITTABLETYPEINT_H_ */