How to check if a variable is a member of a set

I'm trying to see if a certain number is equal to a very limited set of numbers. I have the following code:

int TestNumber = 192;
Serial.print("The number is ");
Serial.println(TestNumber);
if (TestNumber !=(0,128,192,224,240,248,252,254,255)){
    Serial.println("It is not a member of the set");
  }
  else {
    Serial.println("It is a member of the set");
  }

And I get the following output:

The number is 192
It is not a member of the set

However, if I change TestNumber to 255, I get

The number is 255
It is a member of the set

I don't know what I'm missing. :frowning:

A variable can not be a member of a set. The VALUE in the variable may be one of the values in a list. But, you must compare the value to each of the values in the set. Using an array makes that trivial.

You can not invent new syntax, though.

HazardsMind:
You need to make “(0,128,192,224,240,248,252,254,255)” into an array first.
Then using this,

void loop() {

.
check(TestNumber, array);
.
}// end of loop



void check(int TestNumber, int * array) 
{ 
for(int count = 0; count < (sizeof(array)/2) ; count++) 
{
if(TestNumber != array[count]) return 0;
}
return 1;

I don’t see how returning a value in the loop function will get you anywhere. You would probably want that code in its own function.

HazardsMind:
I fixed it.

Still needs some work - sizeof will give the size of the pointer (2), not the array. Also, the loop doesn't check all numbers - if the number sought is the first in the array, it works, otherwise it returns false without testing the others.

Im an idiot, I took that other one from my password sketch.

#define Asizeof(array) sizeof(array)/sizeof(array[0])

array[] = { /* your numbers here */};
boolean found = false;

for(int count = 0; count < Asizeof(array) ; count++) 
{
 if(TestNumber == array[count])// you can modify this to count how many times the test number occurs too
  { 
    found = true; // number was found,
    break;  //now get out of for loop. 
  }
  found = false; // number was not found
}

if(found == true) //good message
else //bad message

I ended up taking a little bit of everyone's feedback, and brute-forcing it:

int TestNumber = 191;
int subnetreturnvalue = subnetcheck(TestNumber);
Serial.print("Subnet number is ");
Serial.println(TestNumber);
Serial.print("Subnet check returned ");
Serial.println(subnetreturnvalue);

int subnetcheck(int TestNumber) 
// 0 if OK, 1 if failed
{ 
  Serial.println();
switch(TestNumber)
{
case 0: 
  Serial.print("0, "); 
  return 0;
  break;

case 128: 
  Serial.print("128, "); 
  return 0;
  break;

case 192: 
  Serial.print("192, "); 
  return 0;
  break;

case 224: 
  Serial.print("224, "); 
  return 0;
  break;
  
case 240: 
  Serial.print("240, "); 
  return 0;
  break;
  
case 248: 
  Serial.print("248, "); 
  return 0;
  break;

case 252: 
  Serial.print("252, "); 
  return 0;
  break;

case 254: 
  Serial.print("254, "); 
  return 0;
  break;

case 255: 
  Serial.print("255, "); 
  return 0;
  break;
default:
  Serial.print("out "); 
  return 1;
}
}

I opted for this because it's only 9 items in the set. I think I can take the performance hit. :slight_smile:

Thank you all again for your help. :slight_smile:

A little old fashioned, but if it works and you dont mind typing it all out, then go for it.

int subnetcheck(int TestNumber) // 0 if OK, 1 if failed
{ 
  Serial.println();
  switch(TestNumber)
  {
    case 0: 
    case 128: 
    case 192: 
    case 224: 
    case 240: 
    case 248: 
    case 252: 
    case 254: 
    case 255: 
      Serial.print(TestNumber);
      Serial.print(", "); 
      return 0;
    break;
  default:
    Serial.print("out "); 
    return 1;
  }
}

If you're going to brute-force, at least save yourself some typing.

Of course you are not trying to see if a number is a member of a list really, you are trying
to if a byte is of the form 0b111…000 (ones followed by zeroes - or all ones, all zeroes)

There are usually clever bit-bashing methods for such a test. Here that clever test is

  if (testNumber >= 0 && testNumber < 0x100)  // optionally check in 8 bit unsigned range
  {
    byte n = (byte) testNumber ;
    if (((n & -n) + n) == 0)   // clever part
    {
      ...

That’s the first time in a long time I wished we could be transported (and translated) to PASCAL land…

@MarkT: That is pretty impressive. I had noticed the one and zero pattern, but wasn't clever enough to come up with the bit manipulations to make it work.

Allow me to acknowledge your brilliance.

MarkT:

// clever part

You are not wrong!

I know I haven’t been programing any where near as long as you guys have, and I know I still have much to learn, but I dont see how this is a viable solution to the OP problem.

if (testNumber >= 0 && testNumber < 0x100) // optionally check in 8 bit unsigned range
{
byte n = (byte) testNumber ;
if (((n & -n) + n) == 0) // clever part
{

Can someone explain what this is doing?

I can take a shot at it. First, let's look at the binary representation of the 9 values in his set:

0        128      192      224      240      248      252      254      255      
00000000 10000000 11000000 11100000 11110000 11111000 11111100 11111110 11111111

It's easy to see how we could come up with a really easy algorithm to check any given 8 bit value to see if it fits this pattern. But it would be quicker if we could come up with a formula that always worked on these 9 values, and always failed on all the other values. Let's see how MarkT's formula fits various values.

              0         128       192       224       240       248       252       254       255       1         100
n             00000000  10000000  11000000  11100000  11110000  11111000  11111100  11111110  11111111  00000001  01100100
-n            00000000  10000000  01000000  00100000  00010000  00001000  00000100  00000010  00000001  11111111  10011100
n & -n        00000000  10000000  01000000  00100000  00010000  00001000  00000100  00000010  00000001  00000001  00000100
(n & -n) + n  00000000 100000000 100000000 100000000 100000000 100000000 100000000 100000000 100000000  00000010  01101000

You can see that for all the 9 values in the table, the results (ignoring the overflow bit) are all 0. The other values gave other results. I'm too lazy to try all 256 of them right now, but if you want you could run them all and show us the results. I predict none of the other 247 values will give a 0 result.

I'm too lazy to try all 256 of them right now, but if you want you could run them all and show us the results. I predict none of the other 247 values will give a 0 result.

Wouldn't take too long to write a sketch for the Arduino to test that. Of course, I'm too lazy, too.

Ok, now I understand. I added an attachment of my findings

numbers.txt (1.83 KB)

You folks are all amazing. To answer a question that wasn't ever asked, yes the numbers I picked all started with all 1's in binary. It's for a subnet mask for IP addresses. I'm debating whether or not to swap the 3 line solution with the existing 20+ line solution right now. :slight_smile:

Oh, and I removed the Serial.print lines from my switch & case statements. I only left them in there to test. :slight_smile:

That's the first time in a long time I wished we could be transported (and translated) to PASCAL land...

Or APL.

Ah! yes, APL, the world's best write-only language.

MarkT:
Of course you are not trying to see if a number is a member of a list really, you are trying
to if a byte is of the form 0b111…000 (ones followed by zeroes - or all ones, all zeroes)

There are usually clever bit-bashing methods for such a test. Here that clever test is

  if (testNumber >= 0 && testNumber < 0x100)  // optionally check in 8 bit unsigned range

{
    byte n = (byte) testNumber ;
    if (((n & -n) + n) == 0)   // clever part
    {
      …

Well, we ran into a problem. While yes, it’s incredibly clever, it doesn’t work for zero. According to this code:

int subnetchecker(int testNumber) 
// 0 if OK, 1 if failed
{ 
if (testNumber >= 0 && testNumber < 0x100)  // optionally check in 8 bit unsigned range
  {
    byte n = (byte) testNumber ;
    if (((n & -n) + n) == 256)   // clever part EDIT tweaked it
    {
      return 0;
    }
   else return 1;
}
}

it will resolve all but zero properly. Using 255 as an example, this function returns 0. But a zero returns 1. If I use your first example, where it’s == 0 instead of == 256, it’s reversed.

How do we get it to acknowledge zero as a valid subnet octet, without going back to the old case statements?