return inherited::compare_same_type(other);
}
-bool add::is_equal_same_type(const basic & other) const
-{
- return inherited::is_equal_same_type(other);
-}
-
unsigned add::return_type(void) const
{
if (seq.empty())
ex simplify_ncmul(const exvector & v) const;
protected:
ex derivative(const symbol & s) const;
- bool is_equal_same_type(const basic & other) const;
unsigned return_type(void) const;
unsigned return_type_tinfo(void) const;
ex thisexpairseq(const epvector & v, const ex & oc) const;
{
unsigned v = golden_ratio_hash(tinfo());
for (unsigned i=0; i<nops(); i++) {
- v = rotate_left_31(v);
+ v = rotate_left(v);
v ^= (const_cast<basic *>(this))->op(i).gethash();
}
-
- // mask out numeric hashes:
- v &= 0x7FFFFFFFU;
-
+
// store calculated hash value only if object is already evaluated
if (flags & status_flags::evaluated) {
setflag(status_flags::hash_calculated);
return subs(ls, lr, no_pattern);
}
-/** Compare objects to establish canonical ordering.
+extern "C" { int putchar(int c); } // FIXME: removeme
+
+/** Compare objects syntactically to establish canonical ordering.
* All compare functions return: -1 for *this less than other, 0 equal,
* 1 greater. */
int basic::compare(const basic & other) const
if (typeid_this==typeid_other) {
GINAC_ASSERT(typeid(*this)==typeid(other));
// int cmpval = compare_same_type(other);
-// if ((cmpval!=0) && (hash_this<0x80000000U)) {
+// if (cmpval!=0) {
// std::cout << "hash collision, same type: "
// << *this << " and " << other << std::endl;
// this->print(print_tree(std::cout));
// return cmpval;
return compare_same_type(other);
} else {
-// std::cout << "hash collision, different types: "
-// << *this << " and " << other << std::endl;
-// this->print(print_tree(std::cout));
-// std::cout << " and ";
-// other.print(print_tree(std::cout));
-// std::cout << std::endl;
+// std::cout << "hash collision, different types: "
+// << *this << " and " << other << std::endl;
+// this->print(print_tree(std::cout));
+// std::cout << " and ";
+// other.print(print_tree(std::cout));
+// std::cout << std::endl;
return (typeid_this<typeid_other ? -1 : 1);
}
}
-/** Test for equality.
+/** Test for syntactic equality.
* This is only a quick test, meaning objects should be in the same domain.
* You might have to .expand(), .normal() objects first, depending on the
* domain of your computation, to get a more reliable answer.
unsigned constant::calchash(void) const
{
hashvalue = golden_ratio_hash(tinfo() ^ serial);
- // mask out numeric hashes:
- hashvalue &= 0x7FFFFFFFU;
-
+
setflag(status_flags::hash_calculated);
-
+
return hashvalue;
}
v ^= i->rest.gethash();
#if !EXPAIRSEQ_USE_HASHTAB
// rotation spoils commutativity!
- v = rotate_left_31(v);
+ v = rotate_left(v);
v ^= i->coeff.gethash();
#endif // !EXPAIRSEQ_USE_HASHTAB
++i;
}
-
+
v ^= overall_coeff.gethash();
- v &= 0x7FFFFFFFU;
-
+
// store calculated hash value only if object is already evaluated
if (flags &status_flags::evaluated) {
setflag(status_flags::hash_calculated);
size = nearest_power_of_2/hashtabfactor;
if (size<minhashtabsize)
return 0;
- GINAC_ASSERT(hashtabsize<=0x8000000U); // really max size due to 31 bit hashing
+
// hashtabsize must be a power of 2
GINAC_ASSERT((1U << log2(size))==size);
return size;
unsigned expairseq::calc_hashindex(const ex &e) const
{
// calculate hashindex
- unsigned hash = e.gethash();
unsigned hashindex;
- if (is_a_numeric_hash(hash)) {
+ if (is_a<numeric>(e)) {
hashindex = hashmask;
} else {
- hashindex = hash &hashmask;
+ hashindex = e.gethash() & hashmask;
// last hashtab entry is reserved for numerics
if (hashindex==hashmask) hashindex = 0;
}
- GINAC_ASSERT(hashindex>=0);
GINAC_ASSERT((hashindex<hashtabsize)||(hashtabsize==0));
return hashindex;
}
{
unsigned v = golden_ratio_hash(golden_ratio_hash(tinfo()) ^ serial);
for (unsigned i=0; i<nops(); i++) {
- v = rotate_left_31(v);
+ v = rotate_left(v);
v ^= this->op(i).gethash();
}
- v &= 0x7FFFFFFFU;
+
if (flags & status_flags::evaluated) {
setflag(status_flags::hash_calculated);
hashvalue = v;
//
// Bareiss (fraction-free) elimination in addition divides that element
// by m[k-1](k-1,k-1) for k>1, where it can be shown by means of the
- // Sylvester determinant that this really divides m[k+1](r,c).
+ // Sylvester identity that this really divides m[k+1](r,c).
//
// We also allow rational functions where the original prove still holds.
// However, we must care for numerator and denominator separately and
return inherited::compare_same_type(other);
}
-bool mul::is_equal_same_type(const basic & other) const
-{
- return inherited::is_equal_same_type(other);
-}
-
unsigned mul::return_type(void) const
{
if (seq.empty()) {
// expression like (4^(1/3))^(3/2)
if (are_ex_trivially_equal(c,_ex1))
return split_ex_to_pair(e);
-
+
return split_ex_to_pair(power(e,c));
}
// expression like (4^(1/3))^(3/2)
if (are_ex_trivially_equal(c,_ex1))
return p;
-
+
return split_ex_to_pair(power(recombine_pair_to_ex(p),c));
}
if (ex_to<numeric>(p.coeff).is_equal(_num1))
return p.rest;
else
- return power(p.rest,p.coeff);
+ return (new power(p.rest,p.coeff))->setflag(status_flags::dynallocated);
}
bool mul::expair_needs_further_processing(epp it)
{
- if (is_exactly_a<mul>((*it).rest) &&
- ex_to<numeric>((*it).coeff).is_integer()) {
+ if (is_exactly_a<mul>(it->rest) &&
+ ex_to<numeric>(it->coeff).is_integer()) {
// combined pair is product with integer power -> expand it
*it = split_ex_to_pair(recombine_pair_to_ex(*it));
return true;
}
- if (is_exactly_a<numeric>((*it).rest)) {
- expair ep=split_ex_to_pair(recombine_pair_to_ex(*it));
+ if (is_exactly_a<numeric>(it->rest)) {
+ expair ep = split_ex_to_pair(recombine_pair_to_ex(*it));
if (!ep.is_equal(*it)) {
// combined pair is a numeric power which can be simplified
*it = ep;
return true;
}
- if (ex_to<numeric>((*it).coeff).is_equal(_num1)) {
+ if (it->coeff.is_equal(_ex1)) {
// combined pair has coeff 1 and must be moved to the end
return true;
}
ex simplify_ncmul(const exvector & v) const;
protected:
ex derivative(const symbol & s) const;
- bool is_equal_same_type(const basic & other) const;
unsigned return_type(void) const;
unsigned return_type_tinfo(void) const;
ex thisexpairseq(const epvector & v, const ex & oc) const;
// equivalence relation on numbers). As a consequence, 3 and 3.0 share
// the same hashvalue. That shouldn't really matter, though.
setflag(status_flags::hash_calculated);
- hashvalue = golden_ratio_hash(cln::equal_hashcode(cln::the<cln::cl_N>(value))) | 0x80000000U;
+ hashvalue = golden_ratio_hash(cln::equal_hashcode(cln::the<cln::cl_N>(value)));
return hashvalue;
}
extern const numeric I;
extern _numeric_digits Digits;
-// deprecated macro, for internal use only
-#define is_a_numeric_hash(x) ((x)&0x80000000U)
-
// global functions
const numeric exp(const numeric &x);
unsigned lhash = lh.gethash();
unsigned rhash = rh.gethash();
- v = rotate_left_31(v);
+ v = rotate_left(v);
switch(o) {
case equal:
case not_equal:
lhash = rhash;
break;
}
- v = rotate_left_31(v);
+ v = rotate_left(v);
v ^= lhash;
- // mask out numeric hashes:
- v &= 0x7FFFFFFFU;
-
// store calculated hash value only if object is already evaluated
if (flags & status_flags::evaluated) {
setflag(status_flags::hash_calculated);
unsigned symbol::calchash(void) const
{
- // this is where the schoolbook method
- // (golden_ratio_hash(tinfo()) ^ serial)
- // is not good enough yet...
- hashvalue = golden_ratio_hash(golden_ratio_hash(tinfo()) ^ serial);
+ hashvalue = golden_ratio_hash(tinfo() ^ serial);
setflag(status_flags::hash_calculated);
return hashvalue;
}
return 0;
}
-/** Rotate lower 31 bits of unsigned value by one bit to the left
- * (upper bit gets cleared). */
-inline unsigned rotate_left_31(unsigned n)
+/** Rotate bits of unsigned value by one bit to the left. */
+inline unsigned rotate_left(unsigned n)
{
- // clear highest bit and shift 1 bit to the left
- n = (n & 0x7FFFFFFFU) << 1;
-
- // overflow? clear highest bit and set lowest bit
if (n & 0x80000000U)
- n = (n & 0x7FFFFFFFU) | 0x00000001U;
-
- GINAC_ASSERT(n<0x80000000U);
-
+ n = n << 1 | 0x00000001U;
+ else
+ n = n << 1;
return n;
}
-/** Golden ratio hash function for the 31 least significant bits. */
+/** Truncated multiplication with golden ratio, for computing hash values. */
inline unsigned golden_ratio_hash(unsigned n)
{
// This function requires arithmetic with at least 64 significant bits
#if SIZEOF_LONG >= 8
// So 'long' has 64 bits. Excellent! We prefer it because it might be
// more efficient than 'long long'.
- unsigned long l = n * 0x4f1bbcddL;
- return (l & 0x7fffffffU) ^ (l >> 32);
+ unsigned long l = n * 0x4f1bbcddUL;
+ return (unsigned)l;
#elif SIZEOF_LONG_LONG >= 8
// This requires 'long long' (or an equivalent 64 bit type)---which is,
// unfortunately, not ANSI-C++-compliant.
// (Yet C99 demands it, which is reason for hope.)
- unsigned long long l = n * 0x4f1bbcddL;
- return (l & 0x7fffffffU) ^ (l >> 32);
-#elif SIZEOF_LONG_DOUBLE > 8
- // If 'long double' is bigger than 64 bits, we assume that the mantissa
- // has at least 64 bits. This is not guaranteed but it's a good guess.
- // Unfortunately, it may lead to horribly slow code.
- const static long double golden_ratio = .618033988749894848204586834370;
- long double m = golden_ratio * n;
- return unsigned((m - int(m)) * 0x80000000);
+ unsigned long long l = n * 0x4f1bbcddULL;
+ return (unsigned)l;
#else
-#error "No 64 bit data type. You lose."
+ // Do the multiplication manually by splitting n up into the lower and
+ // upper two bytes.
+ const unsigned n0 = (n & 0x0000ffffU);
+ const unsigned n1 = (n & 0xffff0000U) >> 16;
+ return (n0 * 0x0000bcddU) + ((n1 * 0x0000bcddU + n0 * 0x00004f1bU) << 16);
#endif
}