Reputation: 11
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
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
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
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). ULONG_MAX + 1.0
, interpreted as a double, may well be identical to ULONG_MAX
on 64-bit machinesIt's called fixed point arithmetic and there are many resources available on the internet and elsewhere that explain it very well.
Upvotes: 3
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