Reduce the use of DigitalWrite() - arduino-uno

I'm currently doing a circuit which has two seven segment display. Is there any codes to lessen the usage of digitalwrite()? your text
I also found some codes in arduino for a single seven segment to reduce the digitalwrite.
Here is my code
int E1 = 13;
int E2 = 12;
int D1 = 11;
int D2 = 10;
int C1 = 9;
int C2 = 8;
int G1 = 7;
int G2 = 6;
int F1 = 5;
int F2 = 4;
int a1 = 3;
int a2 = 2;
int b1 = 1;
int B2 = 0;
//setting up the pin
void setup()
{
pinMode(E1, OUTPUT);
pinMode(E2, OUTPUT);
pinMode(D1, OUTPUT);
pinMode(D2, OUTPUT);
pinMode(C1, OUTPUT);
pinMode(C2, OUTPUT);
pinMode(G1, OUTPUT);
pinMode(G2, OUTPUT);
pinMode(F1, OUTPUT);
pinMode(F2, OUTPUT);
pinMode(a1, OUTPUT);
pinMode(a2, OUTPUT);
pinMode(b1, OUTPUT);
pinMode(B2, OUTPUT);
}
byte pinNumArr [7]{A1, B1, C1, D1, E1, F1,G1};
byte number7S [10] [7] =
{
{HIGH,HIGH,HIGH,HIGH,HIGH,HIGH, LOW}, // Number 0
{LOW,HIGH,HIGH,LOW,LOW,LOW, LOW}, // Number 1
{HIGH,HIGH,LOW,HIGH,HIGH,LOW,HIGH}, // Number 2
{HIGH,HIGH,HIGH,HIGH,LOW,LOW,HIGH}, // Number 3
{LOW,HIGH,HIGH,LOW,LOW,HIGH,HIGH}, // Number 4
{HIGH,LOW,HIGH,HIGH,LOW,HIGH,HIGH}, // Number 5
{HIGH,LOW,HIGH,HIGH,HIGH,HIGH,HIGH}, // Number 6
{HIGH,HIGH,HIGH,LOW,LOW,LOW,LOW}, // Number 7
{HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH}, // Number 8
{LOW,HIGH,HIGH,HIGH,LOW,HIGH,HIGH} // Number 9
};
void displayNumber(byte value = 0 )
{
for (int idx = 0; idx < 7; idx++)
{
digitalWrite(pinNumArr[idx], number7S[value][idx]);
value = number7S[value][idx];
}
};
void loop()
{
displayNumber();
delay(500);
}
I want to lessen the usage of digitalwrite for double seven segment display

You can do direct port manipulation instead of all those digitalWrite().
Digital pins 0-7 are on PORTD and digital pins 8-13 are on PORTB.
You can set all of the pins in one line like this:
PORTB = B00000000; //Set pin 8-13 LOW
or you could say:
PORTB = B00010100; //Set pin 10 and 12 HIGH, all others low

Related

How to code Arduino used countdown timer (buzzer), 4 pir sensors, and relay? They worked parallel but what I need is work sequentially

How do you program Arduino to do a countdown timer 10 times using a buzzer, then after that, the light will turn on (relay). In addition, 4 PIR sensors will detect movement, if there is movement, the light will turn off for 10 seconds after which the light will turn on again. I already try to code but something feels off because the light is on at the start and the sensor detects when the timer is still running.
Here is the code that I try to code:
#define relayPin 12
#define pirPin1 8
#define pirPin2 9
#define pirPin3 10
#define pirPin4 11
int val1 = 0,val2 = 0, val3 = 0, val4 = 0 ;
long buzzerFrequency = 1000;
float buzzerDuration = 100;
int startNumber = 9; //countdown starts with this number
int endNumber = 0; //countdown ends with this number
const int buzzerPin = 6;
void setup() {
// put your setup code here, to run once:
pinMode(buzzerPin,OUTPUT);
pinMode(relayPin,OUTPUT);
pinMode(pirPin1, INPUT);
pinMode(pirPin2, INPUT);
pinMode(pirPin3, INPUT);
pinMode(pirPin4, INPUT);
Serial.begin(115200);
}
void buzzer(){
if (startNumber >= endNumber) {
for (int i = 0; i <= 1; i++){
tone(buzzerPin,buzzerFrequency,buzzerDuration);
}
delay(1000);
startNumber--;
}
}
void allPir(){
val1 = digitalRead(pirPin1);
val2 = digitalRead(pirPin2);
val3 = digitalRead(pirPin3);
val4 = digitalRead(pirPin4);
if(val1 == HIGH || val2 == HIGH || val3 == HIGH || val4 == HIGH){
digitalWrite(relayPin, HIGH);
Serial.println("Movement! delay 10 second");
Serial.println("Light off");
delay(10000);
}else{
digitalWrite(relayPin, LOW);
Serial.println("No Movement");
Serial.println("Light on");
}
}
void loop() {
// put your main code here, to run repeatedly:
buzzer();
allPir();
}
The countdown should have finished first with a buzzer sound, then the light will turn on, then the PIR sensor will check the environment. How to fix it? and what do I need to add?

Unable to execute interrupt function

Using Mplab ide 5.10 and xc8 compiler for the pic18f4550 I am unable to get the code to get into the interrupt function the goal is to get J to count up in the background until something trigger it to output a value in the lcd. Currently only the lcd display the first message and using ICD 3 the value of J does not change and does not look like the program runs the interrupt function at all
#define _XTAL_FREQ 48000000
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include "lcd.h"
unsigned char j, output = 0, i, outchar;
char buffer[2] = " ";
char Message[ ] = "Hands Position ";
void interrupt timer0_isr();
void lcd_write_cmd(unsigned char cmd);
void lcd_write_data(unsigned char data);
void lcd_strobe(void); // Generate the E pulse
void lcd_init(void);
void interrupt timer0_ISR() // Timer0 Interrupt Service Routine (ISR)
{
if (INTCONbits.TMR0IF) // TMR0IF:- Timer0 Overflow Interrupt Flag Bit
{
TMR0H = 0x48; // Timer0 start value = 0x48E5 for 1 second
TMR0L = 0xE5;
PORTCbits.RC1 = !PORTCbits.RC1; /* external timing check - toggle every 1ms */
if (j <= 4) { //limit up to 7
j++; // Increase count by 1
PORTB = j; // Output to Demultiplexer
} else {
j = 0; // Reset count aftwr it hit 7
PORTB = j; // Output to Demultiplexer
}
INTCONbits.TMR0IF = 0; // Reset TMR0IF at interrupt end
}
}
void main(void) // Main Function
{
ADCON1 = 0x0F;
CMCON = 0x07;
RCONbits.IPEN = 1; // Bit7 Interrupt Priority Enable Bit
INTCONbits.GIEH = 1; // Bit7 Global Interrupt Enable bit
INTCONbits.GIEL = 0; /* turn on low & high interrupts */
T0CONbits.TMR0ON = 1; // Turn on timer
T0CON = 0b00000111; // bit7:0 Stop Timer0
// bit6:0 Timer0 as 16 bit timer
// bit5:0 Clock source is internal
// bit4:0 Increment on lo to hi transition on TOCKI pin
// bit3:0 Prescaler output is assigned to Timer0
// bit2-bit0:111 1:256 prescaler
INTCON2 = 0b10000100; // bit7 :PORTB Pull-Up Enable bit
// 1 All PORTB pull-ups are disabled
// bit2 :TMR0 Overflow Int Priority Bit
// 1 High Priority
TMR0H = 0x48; // Initialising TMR0H
TMR0L = 0xE5; // Initialising TMR0L for 1 second interrupt
INTCONbits.TMR0IE = 1; // bit5 TMR0 Overflow Int Enable bit
INTCONbits.TMR0IF = 0; // bit2 TMR0 Overflow Int Flag bit
// 0 TMR0 register did not overflow
TRISC = 0; /* all outputs */
TRISAbits.TRISA5 = 1; // RA5 is the check for signal from input Multiplexer.
TRISAbits.TRISA0 = 0; // RA0, RA1 & RA2 output to arduino
TRISAbits.TRISA1 = 0;
TRISAbits.TRISA2 = 0;
TRISD = 0x00; // PortD connects to Demultiplexer
TRISB = 0;
lcd_init(); // LCD init
lcd_write_cmd(0x80); // Cursor set at line 1 positon 1
for (i = 0; i < 16; i++) {
outchar = Message[i]; // Store Message in outchar
lcd_write_data(outchar); // Display Message
}
__delay_ms(100);
PORTD = 0x00; // Clear PortD
PORTB = 0;
j = 0; // Start count from 0
while (1) // Main Process
{
if (PORTAbits.RA5 == 1) { // If RA3 detect a signal
switch (j) { // Switch case to determine hand position & output to RA0, RA1 & RA2 to transmit to arduino
case(0):
output = 10;
PORTAbits.RA0 = 0;
PORTAbits.RA1 = 0;
PORTAbits.RA2 = 0;
break;
case(1):
output = 20;
PORTAbits.RA0 = 1;
PORTAbits.RA1 = 0;
PORTAbits.RA2 = 0;
break;
case(2):
output = 30;
PORTAbits.RA0 = 0;
PORTAbits.RA1 = 1;
PORTAbits.RA2 = 0;
break;
case(3):
output = 40;
PORTAbits.RA0 = 1;
PORTAbits.RA1 = 1;
PORTAbits.RA2 = 0;
break;
case(4):
output = 50;
PORTAbits.RA0 = 0;
PORTAbits.RA1 = 0;
PORTAbits.RA2 = 1;
break;
}
lcd_write_cmd(0xC0); // Cursor set at line 2 positon 1
sprintf(buffer, "%d", output); // Convert numbers to character
for (i = 0; i < 2; i++)
lcd_write_data(buffer[i]); // Display Hand Position
}
}
}

Math calculations in arduino

I wrote a code to do a basic calculations with arduino uno. but it returns me a wrong answer for filledPercentage. It is always -1. what is the problem with this?
//include the library code:
#include <LiquidCrystal.h>
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 13, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
int lowLevelDistance =112;
int highLevelDistance = 47;
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
Serial.begin(9600);
}
void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
lcd.setCursor(0, 1);
int currentLevel = 101;
int filledLevel = (lowLevelDistance - currentLevel);
int fullLevel = (lowLevelDistance - highLevelDistance);
int filledPercentage = filledLevel / (fullLevel / 100);
Serial.println(lowLevelDistance);
Serial.println(highLevelDistance);
Serial.println(currentLevel);
Serial.println(filledLevel);
Serial.println(fullLevel);
Serial.println(filledPercentage);
delay(1000);
}
You shouldn't use an integer for the division, your fulllevel / 100 returns 0.65 but then is converted into an integer (truncating it into a 0).
Dividing by 0 throws an error (-1).

bootloader avr atmega128RFA1

I am also working on the bootloader.
I had the problem in the following:
Once the cmd 'B' is received, later, 'F' is received, then I would start to call block load.
static void start_block_flash_load(uint16_t size, uint32_t *addr) {
uint16_t data_word;
uint8_t sreg = SREG;
uint16_t temp;
int i;
uint8_t my_size;
fprintf(lcdout, "B");
cli();
// Disable interrupts
(*addr) <<= 1;
if (size <= SPM_PAGESIZE) {
boot_page_erase(*addr);
boot_spm_busy_wait();
fprintf(lcdout, "%"PRIu16, size);
uint16_t i;
//store all values. PROBLEM here!!!
my_size = 208;
uint8_t buf[SPM_PAGESIZE] = { 0 };
for (i = 0; i < my_size; i++) {
//for (i=0; i<size; i++){
buf[i] = uart_getc();
// lcd_clear();
// lcd_setCursor(0, 2);
// fprintf(lcdout, "%3d", i);
// _delay_ms(500);
}
for (i = 0; i < my_size; i += 2) { //if size is odd, then use do-while
uint16_t w = buf[i];
w += buf[i + 1] << 8; //first one is low byte, second is high???
boot_page_fill((*addr)+i, w);
}
boot_page_write(*addr);
boot_spm_busy_wait();
(*addr) >>= 1;
uart_putc('\r');
} else
uart_putc('?');
boot_rww_enable ();
SREG = sreg;
}
I can see on the lcd that the size of the block is 256. However, when entering the loop to collect data, it will get stuck.
I tested with my_size and I found that only if my_size=208 the program will run further.
The strange thing is that if I put some statements inside the loop, e.g.
lcd_clear();
lcd_setCursor(0, 2);
then 'i' which I printed out on lcd will not go up to 140 something. I put different statements, the 'i' will give different value. That is very strange, since the uart_getc() will not lose data.
What I expect is that the loop will go up to 256. I cannot figure out what happened there.
Please help if you have any idea.
Thanks

efficiently find the first element matching a bit mask

I have a list of N 64-bit integers whose bits represent small sets. Each integer has at most k bits set to 1. Given a bit mask, I would like to find the first element in the list that matches the mask, i.e. element & mask == element.
Example:
If my list is:
index abcdef
0 001100
1 001010
2 001000
3 000100
4 000010
5 000001
6 010000
7 100000
8 000000
and my mask is 111000, the first element matching the mask is at index 2.
Method 1:
Linear search through the entire list. This takes O(N) time and O(1) space.
Method 2:
Precompute a tree of all possible masks, and at each node keep the answer for that mask. This takes O(1) time for the query, but takes O(2^64) space.
Question:
How can I find the first element matching the mask faster than O(N), while still using a reasonable amount of space? I can afford to spend polynomial time in precomputation, because there will be a lot of queries. The key is that k is small. In my application, k <= 5 and N is in the thousands. The mask has many 1s; you can assume that it is drawn uniformly from the space of 64-bit integers.
Update:
Here is an example data set and a simple benchmark program that runs on Linux: http://up.thirld.com/binmask.tar.gz. For large.in, N=3779 and k=3. The first line is N, followed by N unsigned 64-bit ints representing the elements. Compile with make. Run with ./benchmark.e >large.out to create the true output, which you can then diff against. (Masks are generated randomly, but the random seed is fixed.) Then replace the find_first() function with your implementation.
The simple linear search is much faster than I expected. This is because k is small, and so for a random mask, a match is found very quickly on average.
A suffix tree (on bits) will do the trick, with the original priority at the leaf nodes:
000000 -> 8
1 -> 5
10 -> 4
100 -> 3
1000 -> 2
10 -> 1
100 -> 0
10000 -> 6
100000 -> 7
where if the bit is set in the mask, you search both arms, and if not, you search only the 0 arm; your answer is the minimum number you encounter at a leaf node.
You can improve this (marginally) by traversing the bits not in order but by maximum discriminability; in your example, note that 3 elements have bit 2 set, so you would create
2:0 0:0 1:0 3:0 4:0 5:0 -> 8
5:1 -> 5
4:1 5:0 -> 4
3:1 4:0 5:0 -> 3
1:1 3:0 4:0 5:0 -> 6
0:1 1:0 3:0 4:0 5:0 -> 7
2:1 0:0 1:0 3:0 4:0 5:0 -> 2
4:1 5:0 -> 1
3:1 4:0 5:0 -> 0
In your example mask this doesn't help (since you have to traverse both the bit2==0 and bit2==1 sides since your mask is set in bit 2), but on average it will improve the results (but at a cost of setup and more complex data structure). If some bits are much more likely to be set than others, this could be a huge win. If they're pretty close to random within the element list, then this doesn't help at all.
If you're stuck with essentially random bits set, you should get about (1-5/64)^32 benefit from the suffix tree approach on average (13x speedup), which might be better than the difference in efficiency due to using more complex operations (but don't count on it--bit masks are fast). If you have a nonrandom distribution of bits in your list, then you could do almost arbitrarily well.
This is the bitwise Kd-tree. It typically needs less than 64 visits per lookup operation. Currently, the selection of the bit (dimension) to pivot on is random.
#include <limits.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef unsigned long long Thing;
typedef unsigned long Number;
unsigned thing_ffs(Thing mask);
Thing rand_mask(unsigned bitcnt);
#define WANT_RANDOM 31
#define WANT_BITS 3
#define BITSPERTHING (CHAR_BIT*sizeof(Thing))
#define NONUMBER ((Number)-1)
struct node {
Thing value;
Number num;
Number nul;
Number one;
char pivot;
} *nodes = NULL;
unsigned nodecount=0;
unsigned itercount=0;
struct node * nodes_read( unsigned *sizp, char *filename);
Number *find_ptr_to_insert(Number *ptr, Thing value, Thing mask);
unsigned grab_matches(Number *result, Number num, Thing mask);
void initialise_stuff(void);
int main (int argc, char **argv)
{
Thing mask;
Number num;
unsigned idx;
srand (time(NULL));
nodes = nodes_read( &nodecount, argv[1]);
fprintf( stdout, "Nodecount=%u\n", nodecount );
initialise_stuff();
#if WANT_RANDOM
mask = nodes[nodecount/2].value | nodes[nodecount/3].value ;
#else
mask = 0x38;
#endif
fprintf( stdout, "\n#### Search mask=%llx\n", (unsigned long long) mask );
itercount = 0;
num = NONUMBER;
idx = grab_matches(&num,0, mask);
fprintf( stdout, "Itercount=%u\n", itercount );
fprintf(stdout, "KdTree search %16llx\n", (unsigned long long) mask );
fprintf(stdout, "Count=%u Result:\n", idx);
idx = num;
if (idx >= nodecount) idx = nodecount-1;
fprintf( stdout, "num=%4u Value=%16llx\n"
,(unsigned) nodes[idx].num
,(unsigned long long) nodes[idx].value
);
fprintf( stdout, "\nLinear search %16llx\n", (unsigned long long) mask );
for (idx = 0; idx < nodecount; idx++) {
if ((nodes[idx].value & mask) == nodes[idx].value) break;
}
fprintf(stdout, "Cnt=%u\n", idx);
if (idx >= nodecount) idx = nodecount-1;
fprintf(stdout, "Num=%4u Value=%16llx\n"
, (unsigned) nodes[idx].num
, (unsigned long long) nodes[idx].value );
return 0;
}
void initialise_stuff(void)
{
unsigned num;
Number root, *ptr;
root = 0;
for (num=0; num < nodecount; num++) {
nodes[num].num = num;
nodes[num].one = NONUMBER;
nodes[num].nul = NONUMBER;
nodes[num].pivot = -1;
}
nodes[num-1].value = 0; /* last node is guaranteed to match anything */
root = 0;
for (num=1; num < nodecount; num++) {
ptr = find_ptr_to_insert (&root, nodes[num].value, 0ull );
if (*ptr == NONUMBER) *ptr = num;
else fprintf(stderr, "Found %u for %u\n"
, (unsigned)*ptr, (unsigned) num );
}
}
Thing rand_mask(unsigned bitcnt)
{struct node * nodes_read( unsigned *sizp, char *filename)
{
struct node *ptr;
unsigned size,used;
FILE *fp;
if (!filename) {
size = (WANT_RANDOM+0) ? WANT_RANDOM : 9;
ptr = malloc (size * sizeof *ptr);
#if (!WANT_RANDOM)
ptr[0].value = 0x0c;
ptr[1].value = 0x0a;
ptr[2].value = 0x08;
ptr[3].value = 0x04;
ptr[4].value = 0x02;
ptr[5].value = 0x01;
ptr[6].value = 0x10;
ptr[7].value = 0x20;
ptr[8].value = 0x00;
#else
for (used=0; used < size; used++) {
ptr[used].value = rand_mask(WANT_BITS);
}
#endif /* WANT_RANDOM */
*sizp = size;
return ptr;
}
fp = fopen( filename, "r" );
if (!fp) return NULL;
fscanf(fp,"%u\n", &size );
fprintf(stderr, "Size=%u\n", size);
ptr = malloc (size * sizeof *ptr);
for (used = 0; used < size; used++) {
fscanf(fp,"%llu\n", &ptr[used].value );
}
fclose( fp );
*sizp = used;
return ptr;
}
Thing value = 0;
unsigned bit, cnt;
for (cnt=0; cnt < bitcnt; cnt++) {
bit = 54321*rand();
bit %= BITSPERTHING;
value |= 1ull << bit;
}
return value;
}
Number *find_ptr_to_insert(Number *ptr, Thing value, Thing done)
{
Number num=NONUMBER;
while ( *ptr != NONUMBER) {
Thing wrong;
num = *ptr;
wrong = (nodes[num].value ^ value) & ~done;
if (nodes[num].pivot < 0) { /* This node is terminal */
/* choose one of the wrong bits for a pivot .
** For this bit (nodevalue==1 && searchmask==0 )
*/
if (!wrong) wrong = ~done ;
nodes[num].pivot = thing_ffs( wrong );
}
ptr = (wrong & 1ull << nodes[num].pivot) ? &nodes[num].nul : &nodes[num].one;
/* Once this bit has been tested, it can be masked off. */
done |= 1ull << nodes[num].pivot ;
}
return ptr;
}
unsigned grab_matches(Number *result, Number num, Thing mask)
{
Thing wrong;
unsigned count;
for (count=0; num < *result; ) {
itercount++;
wrong = nodes[num].value & ~mask;
if (!wrong) { /* we have a match */
if (num < *result) { *result = num; count++; }
/* This is cheap pruning: the break will omit both subtrees from the results.
** But because we already have a result, and the subtrees have higher numbers
** than our current num, we can ignore them. */
break;
}
if (nodes[num].pivot < 0) { /* This node is terminal */
break;
}
if (mask & 1ull << nodes[num].pivot) {
/* avoid recursion if there is only one non-empty subtree */
if (nodes[num].nul >= *result) { num = nodes[num].one; continue; }
if (nodes[num].one >= *result) { num = nodes[num].nul; continue; }
count += grab_matches(result, nodes[num].nul, mask);
count += grab_matches(result, nodes[num].one, mask);
break;
}
mask |= 1ull << nodes[num].pivot;
num = (wrong & 1ull << nodes[num].pivot) ? nodes[num].nul : nodes[num].one;
}
return count;
}
unsigned thing_ffs(Thing mask)
{
unsigned bit;
#if 1
if (!mask) return (unsigned)-1;
for ( bit=random() % BITSPERTHING; 1 ; bit += 5, bit %= BITSPERTHING) {
if (mask & 1ull << bit ) return bit;
}
#elif 0
for (bit =0; bit < BITSPERTHING; bit++ ) {
if (mask & 1ull <<bit) return bit;
}
#else
mask &= (mask-1); // Kernighan-trick
for (bit =0; bit < BITSPERTHING; bit++ ) {
mask >>=1;
if (!mask) return bit;
}
#endif
return 0xffffffff;
}
struct node * nodes_read( unsigned *sizp, char *filename)
{
struct node *ptr;
unsigned size,used;
FILE *fp;
if (!filename) {
size = (WANT_RANDOM+0) ? WANT_RANDOM : 9;
ptr = malloc (size * sizeof *ptr);
#if (!WANT_RANDOM)
ptr[0].value = 0x0c;
ptr[1].value = 0x0a;
ptr[2].value = 0x08;
ptr[3].value = 0x04;
ptr[4].value = 0x02;
ptr[5].value = 0x01;
ptr[6].value = 0x10;
ptr[7].value = 0x20;
ptr[8].value = 0x00;
#else
for (used=0; used < size; used++) {
ptr[used].value = rand_mask(WANT_BITS);
}
#endif /* WANT_RANDOM */
*sizp = size;
return ptr;
}
fp = fopen( filename, "r" );
if (!fp) return NULL;
fscanf(fp,"%u\n", &size );
fprintf(stderr, "Size=%u\n", size);
ptr = malloc (size * sizeof *ptr);
for (used = 0; used < size; used++) {
fscanf(fp,"%llu\n", &ptr[used].value );
}
fclose( fp );
*sizp = used;
return ptr;
}
UPDATE:
I experimented a bit with the pivot-selection, favouring bits with the highest discriminatory value ("information content"). This involves:
making a histogram of the usage of bits (can be done while initialising)
while building the tree: choosing the one with frequency closest to 1/2 in the remaining subtrees.
The result: the random pivot selection performed better.
Construct a a binary tree as follows:
Every level corresponds to a bit
It corresponding bit is on go right, otherwise left
This way insert every number in the database.
Now, for searching: if the corresponding bit in the mask is 1, traverse both children. If it is 0, traverse only the left node. Essentially keep traversing the tree until you hit the leaf node (BTW, 0 is a hit for every mask!).
This tree will have O(N) space requirements.
Eg of tree for 1 (001), 2(010) and 5 (101)
root
/ \
0 1
/ \ |
0 1 0
| | |
1 0 1
(1) (2) (5)
With precomputed bitmasks. Formally is is still O(N), since the and-mask operations are O(N). The final pass is also O(N), because it needs to find the lowest bit set, but that could be sped up, too.
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* For demonstration purposes.
** In reality, this should be an unsigned long long */
typedef unsigned char Thing;
#define BITSPERTHING (CHAR_BIT*sizeof (Thing))
#define COUNTOF(a) (sizeof a / sizeof a[0])
Thing data[] =
/****** index abcdef */
{ 0x0c /* 0 001100 */
, 0x0a /* 1 001010 */
, 0x08 /* 2 001000 */
, 0x04 /* 3 000100 */
, 0x02 /* 4 000010 */
, 0x01 /* 5 000001 */
, 0x10 /* 6 010000 */
, 0x20 /* 7 100000 */
, 0x00 /* 8 000000 */
};
/* Note: this is for demonstration purposes.
** Normally, one should choose a machine wide unsigned int
** for bitmask arrays.
*/
struct bitmap {
char data[ 1+COUNTOF (data)/ CHAR_BIT ];
} nulmaps [ BITSPERTHING ];
#define BITSET(a,i) (a)[(i) / CHAR_BIT ] |= (1u << ((i)%CHAR_BIT) )
#define BITTEST(a,i) ((a)[(i) / CHAR_BIT ] & (1u << ((i)%CHAR_BIT) ))
void init_tabs(void);
void map_empty(struct bitmap *dst);
void map_full(struct bitmap *dst);
void map_and2(struct bitmap *dst, struct bitmap *src);
int main (void)
{
Thing mask;
struct bitmap result;
unsigned ibit;
mask = 0x38;
init_tabs();
map_full(&result);
for (ibit = 0; ibit < BITSPERTHING; ibit++) {
/* bit in mask is 1, so bit at this position is in fact a don't care */
if (mask & (1u <<ibit)) continue;
/* bit in mask is 0, so we can only select items with a 0 at this bitpos */
map_and2(&result, &nulmaps[ibit] );
}
/* This is not the fastest way to find the lowest 1 bit */
for (ibit = 0; ibit < COUNTOF (data); ibit++) {
if (!BITTEST(result.data, ibit) ) continue;
fprintf(stdout, " %u", ibit);
}
fprintf( stdout, "\n" );
return 0;
}
void init_tabs(void)
{
unsigned ibit, ithing;
/* 1 bits in data that dont overlap with 1 bits in the searchmask are showstoppers.
** So, for each bitpos, we precompute a bitmask of all *entrynumbers* from data[], that contain 0 in bitpos.
*/
memset(nulmaps, 0 , sizeof nulmaps);
for (ithing=0; ithing < COUNTOF(data); ithing++) {
for (ibit=0; ibit < BITSPERTHING; ibit++) {
if ( data[ithing] & (1u << ibit) ) continue;
BITSET(nulmaps[ibit].data, ithing);
}
}
}
/* Logical And of two bitmask arrays; simular to dst &= src */
void map_and2(struct bitmap *dst, struct bitmap *src)
{
unsigned idx;
for (idx = 0; idx < COUNTOF(dst->data); idx++) {
dst->data[idx] &= src->data[idx] ;
}
}
void map_empty(struct bitmap *dst)
{
memset(dst->data, 0 , sizeof dst->data);
}
void map_full(struct bitmap *dst)
{
unsigned idx;
/* NOTE this loop sets too many bits to the left of COUNTOF(data) */
for (idx = 0; idx < COUNTOF(dst->data); idx++) {
dst->data[idx] = ~0;
}
}

Resources