Author Topic: Picking a random bitwise value from a given number  (Read 2526 times)

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Picking a random bitwise value from a given number
« on: November 11, 2011, 04:23:34 am »


               Hi all,

Does anyone know how to do that? For instance, passing 15 to a given function, it randomizes over the contained values (1,2,4 and 8) and returns the picked value.

Thanks in advance.

Kato 
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #1 on: November 11, 2011, 05:04:13 am »


               

Kato_Yang wrote...

Hi all,

Does anyone know how to do that? For instance, passing 15 to a given function, it randomizes over the contained values (1,2,4 and 8) and returns the picked value.

Thanks in advance.

Kato 


const int MAX_BITS = 32;

int RandomBit(int nInteger)
{
if(!nInteger) return FALSE;
int nRandom = Random(MAX_BITS) + 1;
int nBitValue = 1;
int nInt = 1;
while(nInt < nRandom)
  {
  nBitValue *= 2;
  nInt++;
  }
if(!(nInteger & nBitValue))
  return RandomBit(nInteger);
return(nInteger & nBitValue);
}
               
               

               


                     Modifié par WhiZard, 11 novembre 2011 - 05:11 .
                     
                  


            

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #2 on: November 11, 2011, 05:16:20 am »


               Tyvm WhiZard!
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #3 on: November 11, 2011, 10:18:37 am »


               To return a number with a random bit set,within the first 4 bits, you could just use.  

nRandomBit = 1<< Random( 4);
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #4 on: November 11, 2011, 03:29:24 pm »


               

Lightfoot8 wrote...

To return a number with a random bit set,within the first 4 bits, you could just use.  

nRandomBit = 1<< Random( 4);


That would replace my while loop, but what the OP wants is for a random bit that is flagged as TRUE in a number to be returned (e.g. 17 would only return 16 or 1).

EDIT attached is a code shortening per Lightfoot8's suggestion.


const int MAX_BITS = 32;

int RandomBit(int nInteger)
{
if(!nInteger) return FALSE;
int nBitValue = 1 << Random(MAX_BITS);
if(!(nInteger & nBitValue))
  return RandomBit(nInteger);
return(nInteger & nBitValue);
}
               
               

               


                     Modifié par WhiZard, 11 novembre 2011 - 03:35 .
                     
                  


            

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #5 on: November 11, 2011, 04:00:08 pm »


               Very nice indeed. I'm studying the binary arithmetic and bitwise operators so this is instructive to me, thank you both.

Kato
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #6 on: November 11, 2011, 04:51:26 pm »


               Avoid using the 32nd bit. It freaks NWN out in some instances. For example, in this function:

void SetTaskCompleted(object oPC, int nTaskGiver, int nTaskNumber, int nCompleteNext = FALSE, int nVFX = VFX_IMP_KNOCK) {
    string sKey = "TasksCompleted_" + IntToString(((nTaskGiver-1)/7)+1);
    int nTaskOffset = ((nTaskGiver%7)*4);
    int nCompleted = GetLocalInt(oPC, sKey);
    int nTask = nCompleted >> nTaskOffset;
    int nNew, nMask, nCurrent = nTask & 0xF;

    if (nCompleteNext) {
        nNew = ((nCurrent+1)>15 ? 15 : nCurrent+1);
        nNew = nNew << nTaskOffset;
        nMask = 0xF << nTaskOffset;
        nCompleted &= ~nMask;
        nCompleted |= nNew;

    } else {

        nTaskNumber = ((nTaskNumber > 15) ? 15 : nTaskNumber);
        nNew = nTaskNumber << nTaskOffset;
        nMask = 0xF << nTaskOffset;
        nCompleted &= ~nMask;
        if (nTaskNumber >= 1)//if zero we just leave the bits masked out, resetting task chain
            nCompleted |= nNew;
    }

    if (nTaskNumber > 0)
        AssignCommand(GetModule(), DelayCommand(0.1, ApplyVisualToObject(nVFX, oPC)));
    else
        AssignCommand(GetModule(), DelayCommand(0.1, ApplyVisualToObject(VFX_IMP_REDUCE_ABILITY_SCORE, oPC)));

    SetLocalInt(oPC, sKey, nCompleted);
    SetPersistentInt(oPC, sKey, nCompleted);
}

'Task' completion data gets stored for 7 different taskgivers, who are assigned 4 bits each. Because their tasks are sequential, that allowed us to store up to 15 tasks for each of them (as opposed to 4 independant quest states, 1 per bit). Originally, however, it held 8 taskgivers, using the total 32 bits.Bioware's bitmath worked perfectly until the 32nd bit was set, when a player completed that taskgiver's 8th task. Then it bugged the entire setup.

Funky
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #7 on: November 11, 2011, 04:52:55 pm »


               

Kato_Yang wrote...

Very nice indeed. I'm studying the binary arithmetic and bitwise operators so this is instructive to me, thank you both.

Kato


Looking again at the script there is one critical flaw.  For single bit numbers the average number of times the function will be called is 32.  The maximum times NWScript allows for such self-referencing is 125.  There is a 1.8% chance that single bit numbers would cause an overflow number of loopings.  There are two ways around this.  Either 1. decrease MAX_BITS to something like 16, or 2. store the usable bits as local Integers, and return a random local integer.

Below is a script demonstrating method 2.


int RandomBit(int nInteger)
{
if(!nInteger) return FALSE;// If there are no good bits none can be returned
int nBitValue = 1;
int nCount = 0;
while(nBitValue <= nInteger  && nBitValue != 0) // Stores all good bits in one loop
  {
  if(nBitValue & nInteger)
    {
   nCount++;
    SetLocalInt(OBJECT_SELF, "BIT" + IntToString(nCount), nBitValue);
   
    }
  nBitValue << 1;
  }
int nReturn = GetLocalInt(OBJECT_SELF, "BIT" + IntToString(Random(nCount) + 1)); //Get a random stored bit
while(nCount > 0)// Clean up
  {
  DeleteLocalInt(OBJECT_SELF, "BIT" + IntToString(nCount));
  nCount--;
  }
return nReturn;
}


EDIT: Fixed an off by one issue for nCount
               
               

               


                     Modifié par WhiZard, 11 novembre 2011 - 05:00 .
                     
                  


            

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #8 on: November 11, 2011, 05:59:10 pm »


               Okay, certainly. Fortunately, avoiding the 32nd bit is not a problem in the systems I'm using. I did not know about the limit of 125 for recursive calls either, so you guys make my day, thanks again. '<img'>

Kato
               
               

               


                     Modifié par Kato_Yang, 11 novembre 2011 - 06:00 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #9 on: November 11, 2011, 07:56:16 pm »


               

Kato_Yang wrote...

Very nice indeed. I'm studying the binary arithmetic and bitwise operators so this is instructive to me, thank you both.

Kato


ok here is a little more advanced form.  That is if you want to push your understanding.   If not ingnore it,  Also im typing it at work so please excuse any typos.  

int GetRandonBit( int aBitArray)
{
   int aArrayCopy = aBitArray;
   int nCount;
   
   While (aArrayCopy)
   {
      aArrayCopy = (aArrayCopy & - aArrayCopy) ^ aArrayCopy;
      nCount++;
   }
  
   int nRND = Random(nCount);
  
   while ( nCount--) aBitArray= (aBitArray& - aBitArray) ^ aBitArray;
  
   return  aBitArray & - aBitArray;
}

Ill try to comment it when I get home later.
               
               

               


                     Modifié par Lightfoot8, 11 novembre 2011 - 07:59 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #10 on: November 11, 2011, 08:44:54 pm »


               

Lightfoot8 wrote...
ok here is a little more advanced form.  That is if you want to push your understanding.   If not ingnore it,  Also im typing it at work so please excuse any typos.  

int GetRandomBit( int aBitArray)
{
   int aArrayCopy = aBitArray;
   int nCount;
   
   While (aArrayCopy)
   {
      aArrayCopy = (aArrayCopy & - aArrayCopy) ^ aArrayCopy;  //Gets smallest bit and removes it
      nCount++; //Counts the bits
   }
  
   int nRND = Random(nCount);  //0 stays zero, otherwise randomly selects from 0 to one less than nCount
  
   while ( nCount--) aBitArray= (aBitArray& - aBitArray) ^ aBitArray; //removes all bits less than the one designated.
  
   return  aBitArray & - aBitArray;//Returns smallest remaining bit (the one designated), 0 returns 0.
}

Ill try to comment it when I get home later.


Impressive, even returns FALSE for the 0 case.  I've added comments for you, and renamed the function to GetRandomBit().
               
               

               


                     Modifié par WhiZard, 11 novembre 2011 - 08:47 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #11 on: November 11, 2011, 11:36:36 pm »


               

WhiZard wrote...
while ( nCount--)


My eyes jumped over this flaw.  Should be while (nRND--) .
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #12 on: November 12, 2011, 12:30:42 am »


               

WhiZard wrote...

WhiZard wrote...
while ( nCount--)


My eyes jumped over this flaw.  Should be while (nRND--) .


Yep,   sure enough.   
Thank for the added comments.   Looks a lot better the what I would have written.   Since the nCount/ nRND is messed up any way, Might as well just get trime the extra var out and use  nCount for the random number.  

So here it is with Wiz's comments, bug fixes and spelling corrections. 

int GetRandomBit( int aBitArray)
{
   int aArrayCopy = aBitArray;
   int nCount;

   While (aArrayCopy)
   { 
      //Get smallest bit and removes it
      aArrayCopy = (aArrayCopy & - aArrayCopy) ^ aArrayCopy;

      //Count the bits
      nCount++;
   }

   //0 stays zero, otherwise randomly selects from 0 to one less than nCount
   nCount = Random(nCount);

   //remove all bits less than the one designated.
   while ( nCount--) aBitArray= (aBitArray& - aBitArray) ^ aBitArray;
 
  //Returns smallest remaining bit (the one designated), 0 returns 0.
   return  aBitArray & - aBitArray;
}   

 
               
               

               


                     Modifié par Lightfoot8, 12 novembre 2011 - 12:33 .
                     
                  


            

Legacy_Kato -

  • Hero Member
  • *****
  • Posts: 747
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #13 on: November 12, 2011, 12:49:57 am »


               That's some serious coding, Lightfoot, tyvm. I'll have to study this a bit...


Kato
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Picking a random bitwise value from a given number
« Reply #14 on: November 12, 2011, 01:13:27 am »


               

Kato_Yang wrote...

That's some serious coding, Lightfoot, tyvm. I'll have to study this a bit...


Kato


The main concept comes from a post that The.Gray.Fox made.
               
               

               


                     Modifié par Lightfoot8, 12 novembre 2011 - 01:14 .