user3062084
user3062084

Reputation: 11

C - Bit operation without loop

I am trying to calculate a value in function of bits in a word of variable length. Starting MSB, if bit is 1 then the value is 1/2^i. This value is multiplied by a scaling factor

Example: 110010 this would be (1/2 + 1/4 + 1/64) * scaling_factor

I have programmed it with a for loop; any idea of how this could be done avoiding the loop?

This is the code:

double dec_bnr (unsigned long data, int significant_bits, double scaling_factor)
{
    unsigned int temp;
    unsigned int bnr_locmask = 0x8000000;
    temp = data & bnr_locmasks[significant_bits-1];
    double result = 0;

    for (int i=0; i<significant_bits; i++){
        if((temp & bnr_locmask)==bnr_locmask){
            result+=pow (0.5, i+1);
        }
        bnr_locmask = bnr_locmask >> 1;
    }
    return result * scaling_factor;
}

Thank you in advance!

Edit: Thank you for your answers; however, what I am trying to say is not what you propose. Please, let me add an example: data=a0280

A       2   4   8   16  32  64  128 256 512 1024    2048    4096    8192
1/A     0,5     0,125                               0,000488281     0,00012207
data    1   0   1   0   0   0   0   0   0   0        1        0         1   0000000

result = scaling_factor*Sum(data/A)

We only take into account the value 1/A if the bit for that position is 1.

Upvotes: 0

Views: 229

Answers (3)

user3793679
user3793679

Reputation:

Or you could use ldexp():

  double result = ldexp(data * scaling_factor, -significant_bits) ;

which has the advantage of expressing exactly what you are doing ! (Assuming that the scaling_factor is double.)

It also avoids any issues with constructing large powers of two ((double)(ULONG_MAX + 1) doesn't quite work !) and dividing, or doing pow(2.0, -significant_bits) and multiplying.


Further thought... this is, of course, equivalent:

  double result = ldexp((double)data, -significant_bits) * scaling_factor ;

But you could lump the "binary point shift" in with the scaling_factor (once):

  double scaling_factor_x = ldexp(scaling_factor, -significant_bits) ;

and then the conversion is simply:

  double result = (double)data * scaling_factor_x ;

Upvotes: 2

Edward
Edward

Reputation: 7090

It's actually very easy to do without a loop:

double dec_bnr (unsigned long data, double scaling_factor)
{
    return data*scaling_factor/(ULONG_MAX+1.0);
}

It's worth noting what happens in this code. First, data is converted into a double to match scaling_factor and then the numbers are multiplied, but then we do a further scaling dividing by ULONG_MAX+1.0 which is also converted to a double before dividing. Note that

  1. This can't be ULONG_MAX + 1 because that would cause the number to remain an integer type and wrap around to zero (and thus causing a divide-by-zero error at runtime).
  2. The number ULONG_MAX + 1.0, interpreted as a double, may well be identical to ULONG_MAX on 64-bit machines

It's called fixed point arithmetic and there are many resources available on the internet and elsewhere that explain it very well.

Upvotes: 3

David Grayson
David Grayson

Reputation: 87416

This, or something similar, should be equivalent to what you are doing:

(double)data / 0x100000000 * scaling_factor

The way binary works is that each bit has a weight twice the weight of the bit after it, so you don't need to loop through the bits like you are doing.

Upvotes: 0

Related Questions