error in floor

From: Squeak <squeak_at_xirr.com>
Date: Sat, 5 Jun 1999 23:18:20 -0400 (EDT)

Genius 0.4.3
Copyright (c) 1997,1998,1999 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.

genius> floor(73! * 1.0) - 73!
= 0
genius> floor(74! * 1.0) - 74!
= -39306667005013562067473399808
genius> floor(74!) - 74!
= 0
genius> quit

This is the unmodified version.

Basically 74! doesn't fit into a double, so mpf_get_d(74!*1.0) doesn't
return the correct value. FWIW it returns the correct decimal digits, it's
off by a pwoer of 10. (I find that strange to say the least).

FIX: have floor return a mpz_t instead of a double.

The gmp C++ stuff I've written I am currently translating back to C and
I'll pass that along. It has some functions to do this reasonably
correctly.

This example code is untested in C form, but if you want to use it as a
start:

ManI returns the mantissa as an integer.
ExpI returns the power of 2 to multiply the mantissa by to get the
        original number.
Floor does the obvious.
Init is used to take the various fields of an mpz_t and initialize it.
Shift is a wrapper macro for shifting a _signed_ amount.
Cntlz takes an int and tells how many leading (most significant) bits are
        zero. It is a single instruction on many architectures, but a
        somewhat lengthy c routine. gmp contains a definition of it, but
        you have some #define and #include messiness. I'll send a cleaned
        up version with the rest of the C code after its been checked abit
        more.

no warranty, copyright under GPL blah blah:

/* get count_leading_zeros from gmp source. it is a macro that
   calls assembly versions. see longlong.h for details.
 */

int cntlz (mp_limb_t l) { int c; count_leading_zeros(c,l); return c; }

void mpf_manI (mpz_t rop,mpf_srcptr z)
{
        mpz_init_si_ui_limbp (rop,z[0]._mp_size, z[0]._mp_prec + 1,
z[0]._mp_d);
}

mp_exp_t mpf_exp2 (mpf_srcptr z)
{
        return z[0]._mp_size ?
                z[0]._mp_exp * BITS_PER_MP_LIMB - cntlz (z[0]._mp_d[ABS
(z[0]._mp_size) - 1]) - 1 : 0;
}

void mpf_floor (mpz_t rop,mpf_srcptr z)
{
        mpf_manI(rop,z);
        mpz_shift_left(rop,rop,mpf_expI(z));
}

void mpz_init_si_ui_limbp(mpz_t rop,int size,unsigned int alloc,mp_limb_t
* limbs)
{
        rop[0]._mp_size=size;
        rop[0]._mp_alloc=alloc;
        rop[0]._mp_d=malloc(alloc*BYTES_PER_MP_LIMB);
        memcpy(rop[0]._mp_d,limbs,alloc*BYTES_PER_MP_LIMB);
}

void mpz_shift_left (mpz_t rop, mpz_srcptr op1, long shift)
{
        if (shift >= 0)
                mpz_mul_2exp (rop, op1, shift);
        else
                mpz_tdiv_q_2exp (rop, op1, -shift);
}
Received on Sat Jun 05 1999 - 19:50:38 CDT

This archive was generated by hypermail 2.2.0 : Sun Apr 17 2011 - 21:00:02 CDT