Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Math/Algorithm For Determining a Single-Value Enum 2

Status
Not open for further replies.

BoulderBum

Programmer
Jul 11, 2002
2,179
US
For a project I'm working on, I want to determine whether an enum marked with a FlagsAttribute is passed to a function as a single enum value.

e.g.
Code:
//this is should succeed.
MyFunction( MyEnum.SingleValue );

//this should fail
MyFunction( MyEnum.OneValue | MyEnum.OtherValue );

To accomplish the task, I'm checking to see if the enum value log 2 is a whole number:

Code:
 private bool IsSingleValueEnum(Enum enumValue)
{
      int valAsInt = Convert.ToInt32(enumValue);

      //always return true if zero because we assume it's a single value,
      //but it doesn't work with the rest of the algorithm
      if ((int)valAsInt == 0)
          return true;

      //we know that a single bit occupies the space that sits in a space
      //that is 2 to the N-th power, e.g. 2, 4, 8, 16, 32, etc.
      //here we check that we have a whole numer after computing log base 2
      double log2OfPermissionType = Math.Log((double)valAsInt, 2.0);

      //now we check to see if the result is a whole number (which would indicate
      //that we have a single bit value passed in permissionType)
      return (log2OfPermissionType - Math.Floor(log2OfPermissionType)) < double.Epsilon;
}

What I'm wondering, however, is if there might be a more efficient way to determine what I want, either algorithmicly or mathematically (just for fun).

Can anyone see a potential improvement to the process?

 
Hey that's great! Much simpler. I think I'll change my code accordingly.

The only caveat is that the enum needs to start with a non-zero value (or have the non-zero check in the code) because the zero-value Enum won't show up in .ToString().

In other words, this works for comma-delimitted enums with .ToString():

Code:
//Yes!!!
[FlagsAttribute]
enum MultiHue : short
{
   Black = 1,
   Red = 2,
   Green = 4,
   Blue = 8
};

...while this does not work:

Code:
[FlagsAttribute]
//No!!!
enum MultiHue : short
{
   Black = 0, //No!!!
   Red = 1,
   Green = 2,
   Blue = 4
};
 
If you want to do this, don't use 0 as an enum value.
:)

Chip H.


____________________________________________________________________
If you want to get the best response to a question, please read FAQ222-2244 first
 
That's what I was saying in my last post, though you can first check for zero, then check for a comma in .ToString() if you still want to use a zero value.

MCP, MCTS - .NET Framework 2.0 Web Applications
 
Interesting problem. I was checking all the bitwise operators to see if there was anything you could use. All the shift operators lose the bits they shift out - I'd hoped there would be some kind of return value to look at, maybe to increment a counter. Bitwise AND doesn't give any kind of condition that you can check either.

Strange, considering prehistoric IBM kit has had this kind of facility since the '60s.

If performance is an issue (like if you are doing this 5000 times a second), it might be better to test the low order bit, conditionally increment a counter, shift the value right, and loop until you've done all the bits. Then check the counter. It really depends on how much MSIL gets generated by the call to .ToString on an Enum, and the subsequent comma-counting exercise...

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::perlDesignPatterns)[/small]
 
That's not a bad idea. I suspect it's faster than the logarithm approach, too.

In fact, I sat down to do a quick benchmark of all the approaches, and here's what I came up with for 1,000,000 single-bit enum checks in a loop.

1. The original logarithm approach took about .01 seconds.
2. The bit-shifting approach took .009 seconds.
3. The ToString()/comma approach took .1 seconds.

So the bit-shift is an optimization over the logarithm, while the ToString() took about 10x as long as the other approaches.

That being the case, no approach took more than a ten-millionth of a second for a single evaluation, so the simplest approach will suffice for the vast majority of uses.

I think the string/comma approach wins in the simplicity category, so given my situation (where I'm only calling the single-bit check fuction a few times per web request), I think I'll stick with Zathras' suggestion.

This is interesting stuff to me, though!


MCP, MCTS - .NET Framework 2.0 Web Applications
 
me said:
Interesting problem
BoulderBum said:
This is interesting stuff to me, though!
I suspect both of us need to get out more...

Steve

[small]"Every program can be reduced by one instruction, and every program has at least one bug. Therefore, any program can be reduced to one instruction which doesn't work." (Object::perlDesignPatterns)[/small]
 
[lol]

You may be right.

MCP, MCTS - .NET Framework 2.0 Web Applications
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top