Go Down

Topic: HEX and BIn conversion for unsigned long data type wrong (Closed) (Read 332 times) previous topic - next topic

ffokke

For some project I'd like to store boolean parameters into eeprom.
However, I ran into a problem when I got returned a different number than I put in.
After some testing it seems that some conversions are calculated wrong.
In those cases the 1st bit of the second most significant byte is set to 0.
It gets even worse if a variable is used for the most to least significant bytes.
Am I doing something wrong? It ain't a bug?
I can't find anything where this is mentioned.
Nobody would probably use these kind of notations (it's for testing now), but it should work shouldn't it?

Code: [Select]


// When composing a long data type, in certain cases the 1st bit of the 2nd most significant byte (byte 2) is set to 0
// Using a variable for the multiplier even sets all bits of bytes 2 and 3 to 1.

unsigned long calculatedvalue=(B11111111 * 16777216) + (B11111111 * 65536) + (B11111111 * 256) + (B11111111); //Binairy conversion: bit 1 of byte 2 is wrong
//unsigned long calculatedvalue=(0xFF * 16777216) + (0xFF * 65536) + (0xFF * 256) + (0xFF);                     //Hex conversion: bit 1 of byte 2 is wrong
//unsigned long calculatedvalue=(0xFF * 16777216) + (0xFFFFFF);                                                 //Hex conversion: correct.
//unsigned long calculatedvalue=(0xFF * 16777216) + (0xFF * 65536) + (0xFFFF);                                  //Hex conversion: correct.
//unsigned long calculatedvalue=(0xFFFF * 65536) + (0xFF * 256) + (0xFF);                                       //Hex conversion: bit 1 of byte 2 is wrong
//unsigned long calculatedvalue=(0xFFFF * 65536) + (0xFFFF);                                                    //Hex conversion: correct.
//unsigned long calculatedvalue=0xFFFFFFFF;                                                                     //Hex conversion: correct.
//unsigned long calculatedvalue=(255 * 16777216) + (255 * 65536) + (255 * 256) + (255);                         //Decimal: bit 1 of byte 2 is wrong
//unsigned long calculatedvalue=(255 * 16777216) + (16777215);                                                  //Decimal: correct.
//unsigned long calculatedvalue=(255 * 16777216) + (255 * 65536) + (65535);                                     //Decimal: correct.
//unsigned long calculatedvalue=(65535 * 65536) + (255 * 256) + (255);                                          //Decimal: bit 1 of byte 2 is wrong
//unsigned long calculatedvalue=(65535 * 65536) + (65535);                                                      //Decimal: correct.
//unsigned long calculatedvalue=4278190080 + 16711680 + 65280 + 255;                                            //Decimal: correct.
unsigned long expectedValue=4294967295;

// Testing with multiplier via variable.
// Now bytes 2 and 3 are converted to all ones.
// It doesn't matter if the value of the multiplier is in Hex of decimal notation.
int multiplierB0=0x1;       //Multiplier least significant byte
int multiplierB1=0x100;     //Multiplier 2nd least significant byte
int multiplierB2=0x10000;   //Multiplier 2nd most significant byte
int multiplierB3=0x1000000; //Multiplier most significant byte
//unsigned long calculatedvalue=(B10001111 * multiplierB3) + (B10000111 * multiplierB2) + (B10000011 * multiplierB1) + (B10000001);
//unsigned long expectedValue=2407957377;

void setup() {

  Serial.begin(9600);
  while (!Serial) {
    ;
  }
  Serial.println("Binairy:\t\tMost to least significant byte -->");
  Serial.println("\t\t\t3       2       1       0");
  Serial.println("\t\t\t76543210765432107654321076543210");
  Serial.print("Expected value :\t");
  Serial.println(expectedValue, BIN);
  Serial.print("Calculated value :\t");
  Serial.println(calculatedvalue, BIN);
  Serial.println("");
  Serial.println("Hexidecimal:\t\t3 2 1 0");
  Serial.print("Expected value :\t");
  Serial.println(expectedValue, HEX);
  Serial.print("Calculated value :\t");
  Serial.println(calculatedvalue, HEX);

}

void loop() {

}

holmes4


Quote
Am I doing something wrong? It ain't a bug?
Yes you are doing something wrong and it is a bug in your code!

Mark


PaulS

Code: [Select]
int multiplierB2=0x10000;   //Multiplier 2nd most significant byte
int multiplierB3=0x1000000; //Multiplier most significant byte

Will those values actually fit in an int?
The art of getting good answers lies in asking good questions.

Whandall

Switch on the warnings and let the compiler answer your question.

Code: [Select]
Somewhere\Badhexbin\Badhexbin.ino:6:44: warning: integer overflow in expression [-Woverflow]

 unsigned long calculatedvalue = (B11111111 * 16777216) + (B11111111 * 65536) + (B11111111 * 256) + (B11111111); //Binairy conversion: bit 1 of byte 2 is wrong

                                            ^

Somewhere\Badhexbin\Badhexbin.ino:6:91: warning: integer overflow in expression [-Woverflow]

 unsigned long calculatedvalue = (B11111111 * 16777216) + (B11111111 * 65536) + (B11111111 * 256) + (B11111111); //Binairy conversion: bit 1 of byte 2 is wrong

                                                                                           ^
Somewhere\Badhexbin\Badhexbin.ino:26:20: warning: overflow in implicit constant conversion [-Woverflow]

 int multiplierB2 = 0x10000; //Multiplier 2nd most significant byte

                    ^

Somewhere\Badhexbin\Badhexbin.ino:27:20: warning: overflow in implicit constant conversion [-Woverflow]

 int multiplierB3 = 0x1000000; //Multiplier most significant byte

                    ^
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

septillion

If you want to store bools in EEPROM why don't you just do that?

Or do you want to pack 8 bools into a single byte? If so do simple bitwise operators or use bitWrite() and bitRead().
Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

ffokke

Code: [Select]
int multiplierB2=0x10000;   //Multiplier 2nd most significant byte
int multiplierB3=0x1000000; //Multiplier most significant byte

Will those values actually fit in an int?
Code: [Select]
int multiplierB2=0x10000;   //Multiplier 2nd most significant byte
int multiplierB3=0x1000000; //Multiplier most significant byte

Will those values actually fit in an int?
Right! Of course! Thanks!

ffokke

Switch on the warnings and let the compiler answer your questions.
I'll do. Didn't know that option.
Thanks a lot for helping this newbie.

Whandall

I think having warnings disabled as a default is a bad decision of the arduino team.
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

ffokke

If you want to store bools in EEPROM why don't you just do that?

Or do you want to pack 8 bools into a single byte? If so do simple bitwise operators or use bitWrite() and bitRead().
8, 16, 32... don't know yet.
Was just playing around.
16 went ok, but 32 turned out a bit more difficult.
I did find bitshifting and bitWrite etc. Thanks
I may end up using that.

PaulRB

32 bit should have worked fine. Its 64 bits where bitRead()/bitWrite() don't work. Post your 32 bit code.

GolamMostafa

32 bit should have worked fine. Its 64 bits where bitRead()/bitWrite() don't work. Post your 32 bit code.
The execution of the following codes does not support your opinion?
Code: [Select]
void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);  //L is OFF
  uint64_t x = 0x8234567812345678;//1000 0010 0011 0100 0101 0110 0111 1000, ..., 1000.
  bool n = bitRead(x,63);
  Serial.print(n, BIN); //shows 1
  bitWrite(PORTB, 5, bitRead(x, 63)); //L is ON
}

void loop()
{

}

oqibidipo

bitRead() works with 64-bit values, but bitSet(), bitClear() and bitWrite() are limited to 32 bits because of that 1UL in the macros:

Code: [Select]
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#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))

GolamMostafa

bitRead() works with 64-bit values, but bitSet(), bitClear() and bitWrite() are limited to 32 bits because of that 1UL in the macros:

Code: [Select]
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#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))


Thanks with for the valuable information.

septillion

8, 16, 32... don't know yet.
Was just playing around.
My point was, each EEPROM address can only hold a single byte aka 8-bit. Yeas, with .put() you can place a 16 or 32-bit value in EEPROM but it's then split into 2/4 bytes again. Aka, going beyond 8-bits is a bit pointless. Otherwise you do stuff to pack it and the first thing .put() does is splitting it again.
Use fricking code tags!!!!
I want x => I would like x, I need help => I would like help, Need fast => Go and pay someone to do the job...

NEW Library to make fading leds a piece of cake
https://github.com/septillion-git/FadeLed

Go Up