How to increase extended range floating point multiplier more efficiently?

I do a calculation that often includes values ​​like 3.47493E + 17298. This is much higher than double can handle, and I don't need extra precision, just an extra range of exponents, so I created my own small structure in C #.

My structure uses long for sign and sign, and int for exponent, so I have:

1 sign bit 32 exponential bits (regular 2 component metric) 63 significant bits

I am curious about what steps can be taken to make my multiplication procedure more efficient. I start a huge number of multiplications of these extended range values, and it is pretty fast, but I was looking for clues to speed it up.

My multiplication procedure:

    public static BigFloat Multiply(BigFloat left, BigFloat right)
    {
        long shsign1;
        long shsign2;

        if (left.significand == 0)
        {
            return bigZero;
        }

        if (right.significand == 0)
        {
            return bigZero;
        }

        shsign1 = left.significand;
        shsign2 = right.significand;

        // scaling down significand to prevent overflow multiply

        // s1 and s2 indicate how much the left and right 
        // significands need shifting.
        // The multLimit is a long constant indicating the
        // max value I want either significand to be
        int s1 = qshift(shsign1, multLimit);
        int s2 = qshift(shsign2, multLimit);

        shsign1 >>= s1;
        shsign2 >>= s2;

        BigFloat r;

        r.significand = shsign1 * shsign2;
        r.exponent = left.exponent + right.exponent + s1 + s2;

        return r;
    }

qshift:

, val, , .

    public static int qshift(long val, long limit)
    {
        long q = val;
        long c = limit;
        long nc = -limit;

        int counter = 0;

        while (q > c || q < nc)
        {
            q >>= 1;
            counter++;
        }

        return counter;
    }
+3
3

...

, . , BigFloat.significand .

ldexp frexp, . .

BigFloat :

  • r.significand = left.significand * right.significand
  • r.exponent = left.exponent + right.exponent
  • tmp = ( r.significand frexp)
  • r.exponent += tmp
  • ( ldexp tmp r.significand)

, frexp ldexp, #. , , C.

...

, ...

, 1 2. float :

r.significand = left.significand * right.significand;
r.exponent = left.exponent + right.exponent;
if (r.significand >= 2) {
    r.significand /= 2;
    r.exponent += 1;
}
assert (r.significand >= 1 && r.significand < 2);  // for debugging...

, , assert(). ( , x 1 2, y 1 2, x * y 1 4, , 2 4.)

.., , .

: -).

[edit, frexp]

BigFloat BigFloat::normalize(BigFloat b)
{
    double temp = b.significand;
    double tempexp = b.exponent;
    double temp2, tempexp2;
    temp2 = frexp(temp, &tempexp2);
    // Need to test temp2 for infinity and NaN here
    tempexp += tempexp2;
    if (tempexp < MIN_EXP)
        // underflow!
    if (tempexp > MAX_EXP)
        // overflow!
    BigFloat r;
    r.exponent = tempexp;
    r.significand = temp2;
}
, "" , , , .

, ...

, , . ; , + -. , frexp() NaN, tempexp2 undefined, .

+2

#, .

-, - #? , ...

, , qshift(); , . Mispredicted .

:

long q = abs(val);
int x = q/nc;
(find next power of 2 bigger than x)

. .

qshift 2. ( # " " (aka. ffs)? , 2, .)

, .

, , . ; .

+1

, , .

.

0
source

All Articles