Ejemplo n.º 1
0
/* Converts a bignum b to a double.  b must be normalized.
   We don't rely on double arithmetic, for it may result
   an error in the LSB from multiple roundings.  Instead we
   extract bits directly from the bignum values array.
   (We use ScmBits API by casting b->values to ScmBits*).
 */
double Scm_BignumToDouble(const ScmBignum *b)
{
    ScmBits *bits = (ScmBits*)b->values;
    ScmBits dst[2];
    int maxbit, exponent;

    /* first, filter out a special case. */
    if (b->size == 0) return 0.0;

    maxbit = Scm_BitsHighest1(bits, 0, b->size*WORD_BITS);
    exponent = maxbit+1023;
#if SIZEOF_LONG >= 8
    SCM_ASSERT(maxbit >= 54);   /* because b is normalized */
    dst[0] = 0;
    Scm_BitsCopyX(dst, 0, bits, maxbit-52, maxbit);
    /* Rounding.  We have to round up if maxbit-53 == 1, EXCEPT
       the special case where maxbit-52==0, maxbit-53==1, and all
       bits below are 0 (round-to-even rule) */
    if (SCM_BITS_TEST(bits, maxbit-53)
        && ((dst[0]&1) == 1
            || (Scm_BitsCount1(bits, 0, maxbit-53) > 0))) {
        dst[0]++;
        if (dst[0] >= (1UL<<52)) {
            /* Overflow.  We mask the hidden bit, then shift. */
            dst[0] &= ~(1UL<<52);
            dst[0] >>= 1;
            exponent++;
        }
Ejemplo n.º 2
0
void Scm_BitsCopyX(ScmBits *target, int tstart,
                   ScmBits *src, int sstart, int send)
{
    if (tstart%SCM_WORD_BITS == 0
        && sstart%SCM_WORD_BITS == 0
        && send%SCM_WORD_BITS == 0) {
        /* easy path */
        int tw = tstart/SCM_WORD_BITS;
        int sw = sstart/SCM_WORD_BITS;
        int ew = send/SCM_WORD_BITS;
        while (sw < ew) target[tw++] = src[sw++];
    } else {
        /* TODO: make this more efficient. */
        int t, s;
        for (t=tstart, s=sstart; s < send; t++, s++) {
            if (SCM_BITS_TEST(src, s)) SCM_BITS_SET(target, t);
            else                       SCM_BITS_RESET(target, t);
        }
    }
}