/* Return the ratio n/d reduced so that there are no common factors. */ static inline gnc_numeric reduce128(qofint128 n, gint64 d) { gint64 t; gint64 num; gint64 denom; gnc_numeric out; qofint128 red; t = rem128 (n, d); num = d; denom = t; /* The strategy is to use Euclid's algorithm */ while (denom > 0) { t = num % denom; num = denom; denom = t; } /* num now holds the GCD (Greatest Common Divisor) */ red = div128 (n, num); if (red.isbig) { return gnc_numeric_error (GNC_ERROR_OVERFLOW); } out.num = red.lo; if (red.isneg) out.num = -out.num; out.denom = d / num; return out; }
/* * When decoding, this routine is called to figure out which symbol * is presently waiting to be decoded. This routine expects to get * the current model scale in the s->scale parameter, and it returns * a count that corresponds to the present floating point code: * * code = count / s->scale */ unsigned long long get_current_count( SYMBOL *s ) { unsigned long long range = (unsigned long long) ( high - low ) + 1; unsigned long long z = (unsigned long long)(code - low) + 1; qofint128 one = {0, 1, 1, 0}; qofint128 a = mult128(z, s->scale); qofint128 b = add128(a, one); qofint128 c = div128(b, range); return c.lo; }
/* * This routine is called to encode a symbol. The symbol is passed * in the SYMBOL structure as a low count, a high count, and a range, * instead of the more conventional probability ranges. The encoding * process takes two steps. First, the values of high and low are * updated to take into account the range restriction created by the * new symbol. Then, as many bits as possible are shifted out to * the output stream. Finally, high and low are stable again and * the routine returns. */ void encode_symbol( FILE *stream, SYMBOL *s ) { unsigned long long range; range = (unsigned long long) ( high-low ) + 1; high = SafeConvert(div128(mult128(range, s->high_count), s->scale).lo + low - 1); low = SafeConvert(div128(mult128(range, s->low_count), s->scale).lo + low); /* * This loop turns out new bits until high and low are far enough * apart to have stabilized. */ for ( ; ; ) { /* * If this test passes, it means that the MSDigits match, and can * be sent to the output stream. */ if ( ( high & LAST_BIT ) == ( low & LAST_BIT ) ) { output_bit( stream, high & LAST_BIT ); while ( underflow_bits > 0 ) { output_bit( stream, ~high & LAST_BIT ); underflow_bits--; } } /* * If this test passes, the numbers are in danger of underflow, because * the MSDigits don't match, and the 2nd digits are just one apart. */ else if ( ( low & NEXT_TO_LAST_BIT ) && !( high & NEXT_TO_LAST_BIT )) { underflow_bits += 1; low &= NEXT_TO_LAST_BIT_MINUS_ONE; high |= NEXT_TO_LAST_BIT; } else return ; low <<= 1; high <<= 1; high |= 1; } }
/* * Just figuring out what the present symbol is doesn't remove * it from the input bit stream. After the character has been * decoded, this routine has to be called to remove it from the * input stream. */ void remove_symbol_from_stream( FILE *stream, SYMBOL *s ) { unsigned long long range; range = (unsigned long long) ( high-low ) + 1; high = SafeConvert(div128(mult128(range, s->high_count), s->scale).lo + low - 1); low = SafeConvert(div128(mult128(range, s->low_count), s->scale).lo + low); /* * Next, any possible bits are shipped out. */ for ( ; ; ) { /* * If the MSDigits match, the bits will be shifted out. */ if ( ( high & LAST_BIT ) == ( low & LAST_BIT ) ) { } /* * Else, if underflow is threatining, shift out the 2nd MSDigit. */ else if ((low & NEXT_TO_LAST_BIT) == NEXT_TO_LAST_BIT && (high & NEXT_TO_LAST_BIT) == 0 ) { code ^= NEXT_TO_LAST_BIT; low &= NEXT_TO_LAST_BIT_MINUS_ONE; high |= NEXT_TO_LAST_BIT; } /* * Otherwise, nothing can be shifted out, so I return. */ else return; low <<= 1; high <<= 1; high |= 1; code <<= 1; code += input_bit( stream ); } }
Interval::uint64 CodeInterval::descale(Interval::uint64 value) const throw(not_normalized, range_error) { if(!is_normalized()) { throw not_normalized("Interval must be normalized before descale."); } if(!includes(value)) { throw range_error("Value not in interval."); } // value = (value - base) · 2⁶⁴ / (range + 1) if(range == max) { return value - base; } else { assert(value - base < range + 1); std::uint64_t q, r; std::tie(q, r) = div128(value - base, 0, range + 1); q += (r >= msb) ? 1 : 0; return q; } }
gnc_numeric gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how) { gnc_numeric out; gnc_numeric temp; gint64 temp_bc; gint64 temp_a; gint64 remainder; gint64 sign; gint denom_neg = 0; double ratio, logratio; double sigfigs; qofint128 nume, newm; temp.num = 0; temp.denom = 0; if (gnc_numeric_check(in)) { return gnc_numeric_error(GNC_ERROR_ARG); } if (denom == GNC_DENOM_AUTO) { switch (how & GNC_NUMERIC_DENOM_MASK) { default: case GNC_HOW_DENOM_LCD: /* LCD is meaningless with AUTO in here */ case GNC_HOW_DENOM_EXACT: return in; break; case GNC_HOW_DENOM_REDUCE: /* reduce the input to a relatively-prime fraction */ return gnc_numeric_reduce(in); break; case GNC_HOW_DENOM_FIXED: if (in.denom != denom) { return gnc_numeric_error(GNC_ERROR_DENOM_DIFF); } else { return in; } break; case GNC_HOW_DENOM_SIGFIG: ratio = fabs(gnc_numeric_to_double(in)); if (ratio < 10e-20) { logratio = 0; } else { logratio = log10(ratio); logratio = ((logratio > 0.0) ? (floor(logratio) + 1.0) : (ceil(logratio))); } sigfigs = GNC_HOW_GET_SIGFIGS(how); if (fabs(sigfigs - logratio) > 18) return gnc_numeric_error(GNC_ERROR_OVERFLOW); if (sigfigs - logratio >= 0) { denom = (gint64)(pow(10, sigfigs - logratio)); } else { denom = -((gint64)(pow(10, logratio - sigfigs))); } how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK; break; } } /* Make sure we need to do the work */ if (in.denom == denom) { return in; } if (in.num == 0) { out.num = 0; out.denom = denom; return out; } /* If the denominator of the input value is negative, get rid of that. */ if (in.denom < 0) { in.num = in.num * (- in.denom); /* BUG: overflow not handled. */ in.denom = 1; } sign = (in.num < 0) ? -1 : 1; /* If the denominator is less than zero, we are to interpret it as * the reciprocal of its magnitude. */ if (denom < 0) { /* XXX FIXME: use 128-bit math here ... */ denom = - denom; denom_neg = 1; temp_a = (in.num < 0) ? -in.num : in.num; temp_bc = in.denom * denom; /* BUG: overflow not handled. */ remainder = temp_a % temp_bc; out.num = temp_a / temp_bc; out.denom = - denom; } else { /* Do all the modulo and int division on positive values to make * things a little clearer. Reduce the fraction denom/in.denom to * help with range errors */ temp.num = denom; temp.denom = in.denom; temp = gnc_numeric_reduce(temp); /* Symbolically, do the following: * out.num = in.num * temp.num; * remainder = out.num % temp.denom; * out.num = out.num / temp.denom; * out.denom = denom; */ nume = mult128 (in.num, temp.num); newm = div128 (nume, temp.denom); remainder = rem128 (nume, temp.denom); if (newm.isbig) { return gnc_numeric_error(GNC_ERROR_OVERFLOW); } out.num = newm.lo; out.denom = denom; } if (remainder) { switch (how & GNC_NUMERIC_RND_MASK) { case GNC_HOW_RND_FLOOR: if (sign < 0) { out.num = out.num + 1; } break; case GNC_HOW_RND_CEIL: if (sign > 0) { out.num = out.num + 1; } break; case GNC_HOW_RND_TRUNC: break; case GNC_HOW_RND_PROMOTE: out.num = out.num + 1; break; case GNC_HOW_RND_ROUND_HALF_DOWN: if (denom_neg) { if ((2 * remainder) > in.denom * denom) { out.num = out.num + 1; } } else if ((2 * remainder) > temp.denom) { out.num = out.num + 1; } /* check that 2*remainder didn't over-flow */ else if (((2 * remainder) < remainder) && (remainder > (temp.denom / 2))) { out.num = out.num + 1; } break; case GNC_HOW_RND_ROUND_HALF_UP: if (denom_neg) { if ((2 * remainder) >= in.denom * denom) { out.num = out.num + 1; } } else if ((2 * remainder ) >= temp.denom) { out.num = out.num + 1; } /* check that 2*remainder didn't over-flow */ else if (((2 * remainder) < remainder) && (remainder >= (temp.denom / 2))) { out.num = out.num + 1; } break; case GNC_HOW_RND_ROUND: if (denom_neg) { if ((2 * remainder) > in.denom * denom) { out.num = out.num + 1; } else if ((2 * remainder) == in.denom * denom) { if (out.num % 2) { out.num = out.num + 1; } } } else { if ((2 * remainder ) > temp.denom) { out.num = out.num + 1; } /* check that 2*remainder didn't over-flow */ else if (((2 * remainder) < remainder) && (remainder > (temp.denom / 2))) { out.num = out.num + 1; } else if ((2 * remainder) == temp.denom) { if (out.num % 2) { out.num = out.num + 1; } } /* check that 2*remainder didn't over-flow */ else if (((2 * remainder) < remainder) && (remainder == (temp.denom / 2))) { if (out.num % 2) { out.num = out.num + 1; } } } break; case GNC_HOW_RND_NEVER: return gnc_numeric_error(GNC_ERROR_REMAINDER); break; } } out.num = (sign > 0) ? out.num : (-out.num); return out; }
uint64 burns::mod(const vector<uint64>& x, const monty& k) const { uint64 Xk = k.zero(); uint64 Mk = k.one(); // Try directly calculating the modulus uint64 XM = 0; uint64 W = 0; for(int i=0; i < size(); i++) { const monty& m = mb.field(i); uint64 mk = k.set(m.modulus()); // Xi = X m M⁻¹ mod m uint64 Xi = m.get(m.mul(x[i], mrc[i])); uint64 XiM = div128(Xi, 0, m.modulus()); XM += XiM; if(XM < Xi) W++; // Mk *= m mod k Mk = k.mul(Mk, mk); // Xk += Xi / m mod k Xk = k.add(Xk, k.mul(k.set(Xi), k.inv(mk))); } if((XM + size()) > XM) { // Xk -= W mod k Xk = k.sub(Xk, k.set(W)); // Xk *= M mod k Xk = k.mul(Xk, Mk); // W is certain, return the result return Xk; } // The number of wraps was uncertain, x is very close to zero // // Try again, but add (M - delta) / 3 Xk = 0; XM = 0; W = 0; for(int i=0; i < size(); i++) { const monty& m = mb.field(i); uint64 xi = x[i]; // xi += (M - (M mod 3)) / 3 mod m uint64 Md3 = m.mul(m.sub(m.zero(), m.set(Mmod3)), m.inv(m.set(3))); xi = m.add(xi, Md3); // Xi = X m M⁻¹ mod m uint64 Xi = m.get(m.mul(xi, mrc[i])); uint64 XiM = div128(Xi, 0, m.modulus()); XM += XiM; if(XM < Xi) W++; // Xk += Xi / m mod k Xk = k.add(Xk, k.mul(k.set(Xi), k.inv(k.set(m.modulus())))); } // Xk -= W mod k Xk = k.sub(Xk, k.set(W)); // Xk *= M mod k Xk = k.mul(Xk, Mk); // Xm -= (M - 1) / 3 mod k Xk = k.sub(Xk, k.mul(k.sub(Mk, k.set(Mmod3)), k.inv(k.set(3)))); return Xk; }
uint64 burns::count_wraps(const vector<uint64>& x) const { uint64 Xm = 0; uint64 XM = 0; uint64 W = 0; for(int i=0; i < size(); i++) { const monty& m = mb.field(i); // Xi = X m M⁻¹ mod m uint64 Xi = m.get(m.mul(x[i], mrc[i])); uint64 XiM = div128(Xi, 0, m.modulus()); XM += XiM; if(XM < Xi) W++; // Xm += Xi / m mod 2⁶⁴ Xm += Xi * inv_mod64(m.modulus()); } if((XM + size()) > XM) { // Xm -= W mod 2⁶⁴ Xm -= W; // Xm *= M mod 2⁶⁴ Xm *= Mmod64; // W is certain, return the result return W; } // W is uncertain, could be either W or W + 1 // Resolve by calculating mod64 // What are the chances of a mod64 collision? // Try again, but add (M + 1) / 2 Xm = 0; XM = 0; W = 0; for(int i=0; i < size(); i++) { const monty& m = mb.field(i); uint64 xi = x[i]; // xi += (M + 1) / 2 mod m = 2^-1 mod m // TODO: create a m.half() function, is it faster? xi = m.add(xi, m.inv(m.set_small(2))); // Xi = X m M⁻¹ mod m uint64 Xi = m.get(m.mul(xi, mrc[i])); uint64 XiM = div128(Xi, 0, m.modulus()); XM += XiM; if(XM < Xi) W++; // Xm += Xi / m mod 2⁶⁴ Xm += Xi * inv_mod64(m.modulus()); } // Xm -= W mod 2⁶⁴ Xm -= W; // Xm *= M mod 2⁶⁴ Xm *= Mmod64; // Xm -= (M + 1) / 2 mod 2⁶⁴ Xm -= M2mod64; return Xm; }