Esempio n. 1
0
/* 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;
}
Esempio n. 2
0
/*
 * 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;
}
Esempio n. 3
0
/*
 * 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;
    }
}
Esempio n. 4
0
/*
 * 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 );
    }
}
Esempio n. 5
0
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;
	}
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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;
}