I need to multiply a value by .625 at one point,
Multiply 'x' by 0.625, result is placed in 'out'.
out = x >> 1;
out += x >> 3;
out = temp = x >> 1;
temp >>= 2;
out += temp;
Doing all that shifting probably isn't much more efficient than going (x * 5) / 8, especially since any half-decent compiler ought to optimize the / 8 away (right?).
Doing all that shifting probably isn't much more efficient than going (x * 5) / 8, especially since any half-decent compiler ought to optimize the / 8 away (right?).
yeah, but its always good to understand whats happening and why its fast.
Doing all that shifting probably isn't much more efficient than going (x * 5) / 8, especially since any half-decent compiler ought to optimize the / 8 away (right?). (x * 5) >> 3 if you want to be pedantic, it's one less operation that two shifts and an addition. (Your method will never overflow though, that's a good feature).
Code: [Select]// Do the calculation as integer math...
// The value 640 was pre-calculated.. 0.625 * 1024 = 640.
// need to cast so the calculation is done as 32bit
temp = (uint32_t)(value) * 640;
temp = value * 640ul;
First,
While it was pointed out earlier to do the math in 32 bits, but it was not clearly explained. For someone who doesn't yet understand int vs float for (x*5/8), it may be beneficial to explained:
The multiply is done first to preserve as much precision as feasible, but multiply int16 with another number could overflow the int16. So the multiply should be done in 32 bit.
First,
While it was pointed out earlier to do the math in 32 bits, but it was not clearly explained. For someone who doesn't yet understand int vs float for (x*5/8), it may be beneficial to explained:
The multiply is done first to preserve as much precision as feasible, but multiply int16 with another number could overflow the int16. So the multiply should be done in 32 bit.
In general terms yes. On an ATTiny, 32 bit multiplications are a good way of losing large numbers of clock cycles.
First,
While it was pointed out earlier to do the math in 32 bits, but it was not clearly explained. For someone who doesn't yet understand int vs float for (x*5/8), it may be beneficial to explained:
The multiply is done first to preserve as much precision as feasible, but multiply int16 with another number could overflow the int16. So the multiply should be done in 32 bit.
In general terms yes. On an ATTiny, 32 bit multiplications are a good way of losing large numbers of clock cycles.
The important part is the OP needs to understand is why multiply must occur first, and then to ascertain if multiply must be done in 32 bit.
As to whether the multiply should be converted to bit-shifting and add, or to incorporate rounding or not: Once the ideas or expressions (shown in my demo code result3,4,5,6,7) are understood, shift vs multiply, rounding or not, etc., are simple trade off decision between speed and code readability.
The "something (code) for you to try" demonstrates unless one is sure the expected range of numbers are small enough to avoid overflow, or is large enough that (y/8) precision lost is okay, multiply must be done first and 32bit multiply must be used.
So, he should have some fruit for thought.
0.625 is a nice number because it can be expressed by a small number of binary factors:Code: [Select]out = x >> 1;
out += x >> 3;
0.625 is a nice number because it can be expressed by a small number of binary factors:Code: [Select]out = x >> 1;
out += x >> 3;
If I try this with x=101 I get out=62. Since 101*0.625 is 63.125 I would expect 63 (or even 64) as the result, but not 62.
I would do:
out = x << 2 + x;
out = out >> 3;
bit it requires that out and x are able to hold the extra bits without overflow.
if( x & 1 ) frac++;
out = x >> 1;
if( x & 4 ) frac++;
out += x >> 3;
out += frac>>1;
...
You are missing the point, the shift and add solution does not simply replace the multiply by a shift operation in a simple scaling operation. By breaking down the multiplier into a binary polynomial and dealing with each term individually, no scaling is involved.
...
if( x & 1 ) frac++;
out = x >> 1;
if( x & 4 ) frac++;
out += x >> 3;
out += frac>>1;
If you have headroom in the datatype's size, I guess you could just add 1/2 of the divisor to x at the start, that would be faster.