a function that returns zero if INDF is a power of two, else returns non-zero.
Dmitry A. Kiryashov [nzews at MAIL.RU] says:
decf INDF,F ;0/1/others -> Z=0/Z=1/Z=0 incfsz INDF,W ;0? andwf INDF,W return
Was =0 returning Z=0
Was !=0 and power of 2 returning Z=1
Was !=0 and not a power of 2 returning Z=0
Disadvantage: INDF is decremented in this case.
Wouter adds:
the formula is( x - 1 ) & ( x | 0x80 )explanation:
- (x-1) leaves all set bits in place, except the rightmost one, which is 'smeared out' over the lower bits.
- Hence (x-1)&(x) is 0 when there was only one bit set, OR x was 0.
- From x==0 follows (x-1) == 0xFF, and (x-1) & (anything<>0) != 0.
- When only one bit is set the highest bit in (x-1) will be clear, so it has no effect (except in the all clear case, where it has the desired effect) to use (x|0x80).
verification:
#include <stdio.h> int f( int x ){ return ( 0xFF & ( (x - 1) & ( x | 0x80 ) ) ); } int ones( int x ){ int n = 0; while( x > 0 ){ if( x & 1 > 0 ){ n++; } x = x >> 1; } return n; } int main( void ){ int i, j, k; for( i = 0; i < 256; i ++ ){ j = f( i ); k = ones( i ); printf( "%2X %2X %2X %d\n", i, j, k, ( k == 1 ) == ( j == 0 ) ); } return 0; }
Scott Dattalo says:
But it'd probably make more sense to just make this a macro:is_power_of_2 MACRO x decf x,w bsf x,7 andwf x,w endBoth W and the Z bit contain the result.
If you don't wish the register under test to be modified then this is probably the best solution:
is_power_of_2 MACRO x decf x,w movf x,f skpz andwf x,w endor this:
is_power_of_2 MACRO x movlw -1 addwf x,w skpnc andwf x,w end
Questions: