Go Down

Topic: bitSet only sets bits from 0 to 31 (previously to 15) (Read 1 time) previous topic - next topic

local_dani_21

Nov 11, 2013, 08:14 pm Last Edit: Nov 14, 2013, 12:35 pm by local_dani_21 Reason: 1
Hi

I just realised that bitSet() only works for bits 0 to 31. When wanting to set bits higher than 31, I seem to have to use bitWrite(); Is this an error or a wanted behaviour?

Regards,
Dani

Code: [Select]

uint64_t sternbilder = 0;
bitSet(sternbilder, 8); // for bits from 0 to 31
bitWrite(sternbilder, 32, 1); // for bits 32 and above

robtillaart


From Arduino.h

#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))

so bitWrite() is just a call to bitSet()

because  it use   1UL   which is essentially  32bit unsigned it will not work for uint64_t

(thinking about fix)


Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Jantje

Are you sure about your observations?
The code for bitSet is a macro which looks  long compatible to me.
Also bitWrite is a macro using bitSet.
So if bitWrite works for longs; bitSet should as well

Code: [Select]
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))


Best regards
Jantje
Do not PM me a question unless you are prepared to pay for consultancy.
Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -

robtillaart

#3
Nov 11, 2013, 09:05 pm Last Edit: Nov 11, 2013, 09:19 pm by robtillaart Reason: 1
A solution for 64bit values is to define the following macros, as they use explicit an unsigned long long as datatype.
(you include these in the Arduino.h )

Code: [Select]

#define bitSet64(value, bit) ((value) |= (1ULL << (bit)))
#define bitClear64(value, bit) ((value) &= ~(1ULL << (bit)))
#define bitWrite64(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart


A more elaborate solution might be
Code: [Select]

//
//    FILE: .ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE:
//    DATE:
//     URL:
//
// Released to the public domain
//

#define bitSet64(value, bit) ((value) |= (bit<32?1UL:1ULL) <<(bit))
#define bitClear64(value, bit) ((value) &= ~(bit<32?1UL:1ULL) <<(bit))
#define bitWrite64(value, bit, bitvalue) (bitvalue ? bitSet64(value, bit) : bitClear64(value, bit))


void setup()
{
  Serial.begin(115200);
  Serial.println("Start ");

  uint64_t sternbilder = 0;

  for (int i=1; i<65; i*=2)
  {
    bitSet64(sternbilder, i-1);
  }
  Serial.println(sternbilder, BIN);
}

void loop() {}


Note: I have patched Print.h for uint64 - http://forum.arduino.cc/index.php?topic=143584.msg1079973#msg1079973 -
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Jantje

Rob
The existing macros should work for unsigned long, right?
That is from bit 16 to 31
Your proposal is needed for bits 32 to 63
Or did I miss something?
Best regards
Jantje
Do not PM me a question unless you are prepared to pay for consultancy.
Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -

local_dani_21

Rob, you are so fast I'm hardly able to type in your suggestions before you have an even better one :) I patched the Print.h und Print.cpp and included your #definitions for 64bit magic an am very happy that now everything works as expected. Thank you very much - you should add this code to future arduino-IDE-releases!

local_dani_21

Jantje, I think you are right - I think I have gotten the 15 wrong - it seems to be 31 that is the limit with the normal bitSet()-function. Please excuse my misswriting. Dani.

Jantje

Dani
Thanks; I started thinking I was loosing it  :smiley-eek:
Best regards
Jantje
Do not PM me a question unless you are prepared to pay for consultancy.
Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -

local_dani_21

Jantje, you were perfectly present!

robtillaart

It is better to test the sizeof(value) than to test bit,  as bit often bit can be a variable so its value cannot be checked compile time.

Code: [Select]

#define bitSet64(value, bit) ((value) |= (sizeof(value)<5?1UL:1ULL) <<(bit))
#define bitClear64(value, bit) ((value) &= ~(sizeof(value)<5?1UL:1ULL) <<(bit))
#define bitWrite64(value, bit, bitvalue) (bitvalue ? bitSet64(value, bit) : bitClear64(value, bit))


posted as issue - https://github.com/arduino/Arduino/issues/1670 -
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

kowalski

#11
Nov 11, 2013, 11:11 pm Last Edit: Nov 12, 2013, 11:25 am by kowalski Reason: 1
C++ allows us to do things beyond macros. How about a template class for any size bitset? With operator syntax and that is adapted for an 8-bit machine as ATmega328.
Code: [Select]

template<uint16_t N>
class bitset_t {
private:
 uint8_t m_set[(N + 4)/CHARBITS];
public:
 bitset_t()
 {
   empty();
 }
 uint16_t members()
 {
   return (N);
 }
 void empty()
 {
   memset(m_set, 0, sizeof(m_set));
 }
 bool operator[](uint16_t ix)
 {
   if (ix < N)
     return ((m_set[ix / CHARBITS] & _BV(ix & (CHARBITS - 1))) != 0);
   return (false);
 }
 void operator+=(uint16_t ix)
 {
   if (ix < N) m_set[ix / CHARBITS] |= _BV(ix & (CHARBITS - 1));
 }
 void operator-=(uint16_t ix)
 {
   if (ix < N) m_set[ix / CHARBITS] &= ~_BV(ix & (CHARBITS - 1));
 }
 void dump()
 {
   for (uint16_t i = 0; i < N; i++)
     printf("%d", (m_set[i / CHARBITS] & _BV(i & (CHARBITS - 1))) != 0);
   printf("\n");
 }
};


A small test program (as tested on Linux).

Code: [Select]

enum {
 GREEN,
 BLUE,
 YELLOW,
 RED
};
 
int main()
{
 bitset_t<48> b;
 TRACE(b[GREEN]);
 b += GREEN;
 TRACE(b[GREEN]);
 b -= GREEN;
 TRACE(b[GREEN]);
 b += RED;
 b.dump();
 b += YELLOW;
 b.dump();
 b += 47;
 b.dump();
 b += 48;
 b.dump();
 b += 100;
 b.dump();
 return (0);
}


This is the output:

Code: [Select]

b[GREEN] = 0
b[GREEN] = 1
b[GREEN] = 0
000100000000000000000000000000000000000000000000
001100000000000000000000000000000000000000000000
001100000000000000000000000000000000000000000001
001100000000000000000000000000000000000000000001
001100000000000000000000000000000000000000000001


Cheers!

Jantje

Dani
Maybe it is a good idea to change the title of the first post. 15->31
Best regards
Jantje
Do not PM me a question unless you are prepared to pay for consultancy.
Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -

robtillaart


After some testing it became clear that  changing 1UL into 1ULL is enough to support 64 bit. without affecting 32 bit performance.

#define bitSet64(value, bit) ((value) |= (1ULL << (bit )) )
#define bitClear64(value, bit) ((value) &= ~(1ULL <<(bit)))

more about tests,  see - https://github.com/arduino/Arduino/issues/1670 -




Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

local_dani_21


Dani
Maybe it is a good idea to change the title of the first post. 15->31
Best regards
Jantje

I did - hope it helps others.
Thanks again,
Dani

Go Up