getBandgap () different results const long.vs plugging raw numbers ..WHY?

Here's a simple example that I got from nick gammon's forum.

This is to get internal voltage through 1.1v bandgap

void setup(void)
  {
  Serial.begin(115200);
  }
    
void loop(void)
  {
  Serial.println (getBandgap ());
  delay(1000);
  }

[b]const long[/b] InternalReferenceVoltage = 1062;  // Adjust this value to your board's specific internal BG voltage
 
// Code courtesy of "Coding Badly" and "Retrolefty" from the Arduino forum
// results are Vcc * 100
// So for example, 5V would be 500.
int getBandgap () 
  {
  // REFS0 : Selects AVcc external reference
  // MUX3 MUX2 MUX1 : Selects 1.1V (VBG)  
   ADMUX = bit (REFS0) | bit (MUX3) | bit (MUX2) | bit (MUX1);
   ADCSRA |= bit( ADSC );  // start conversion
   while (ADCSRA & bit (ADSC))
     { }  // wait for conversion to complete
   [b]int results = (((InternalReferenceVoltage* 1024) / ADC) + 5) / 10;[/b] 
   return results;
  } // end of getBandgap

Results=467 (Fine)

but if i just leave out

const long InternalReferenceVoltage = 1062;

and just put 1062 directly into the equation as such..

 [b] int results = (((1062 * 1024) / ADC) + 5) / 10; [/b]

the results are erranous - Results=17

Why? I am just putting in the numbers instead of declaring a const long.

Thanks
Shmuel

An int is only 16 bits on some arduino boards.
1062 * 1024 does not fit a 16-bits int

int results = (((1062UL * 1024) / ADC) + 5) / 10;

If you set the "Compiler warnings:" preference to "All" you will see:

sketch_jul13a.ino: In function 'int getBandgap()':
sketch_jul13a.ino:27:25: warning: integer overflow in expression [-Woverflow]
   int results = (((1062 * 1024) / ADC) + 5) / 10;
                         ^
Sketch uses 1898 bytes (5%) of program storage space. Maximum is 32256 bytes.
Global variables use 188 bytes (9%) of dynamic memory, leaving 1860 bytes for local variables. Maximum is 2048 bytes.

I appreciate the reply. But take a look at this. But if so,
even if I use byte and do some "overflow" calculation the result WILL be accurate.

like this
void setup(void)
{
Serial.begin(115200);
}

void loop(void)
{
Serial.println (getBandgap ());
delay(1000);
}

const long InternalReferenceVoltage = 1062; // Adjust this value to your board's specific internal BG voltage

// Code courtesy of "Coding Badly" and "Retrolefty" from the Arduino forum
// results are Vcc * 100
// So for example, 5V would be 500.
int getBandgap ()
{
// REFS0 : Selects AVcc external reference
// MUX3 MUX2 MUX1 : Selects 1.1V (VBG)
ADMUX = bit (REFS0) | bit (MUX3) | bit (MUX2) | bit (MUX1);
ADCSRA |= bit( ADSC ); // start conversion
while (ADCSRA & bit (ADSC))
{ } // wait for conversion to complete
// int results = (((1062* 1024) / ADC) + 5) / 10;
byte results = 1023*5-5000;
return results;
} // end of getBandgap

1023 * 5 =5115....-5000=115
And that's exactly what prints.

So if what you are saying holds true, then why does it "overflow" when I say

int results = (((1062* 1024) / ADC) + 5) / 10;

and not when I say

byte results = 10235-5000;
or
intresults = 1023
5-5000;

1062 * 1024 is 1,087,488 (0x109800) which won't fit in a 16-bit 'int' (32,767 max). It gets truncated to 16 bits (0x9800) to fit. That also makes it a negative number since the 16th bit is set: -26624

1023 * 5 = 5115 That DOES fit in an integer. Subtracting 5000 gets you a value that fits in a byte or integer.

Okay. I just tried this
void setup(void)
{
Serial.begin(115200);
}

void loop(void)
{
Serial.println (getBandgap ());
delay(1000);
}

const long InternalReferenceVoltage = 1062; // Adjust this value to your board's specific internal BG voltage

// Code courtesy of "Coding Badly" and "Retrolefty" from the Arduino forum
// results are Vcc * 100
// So for example, 5V would be 500.
int getBandgap ()
{
// REFS0 : Selects AVcc external reference
// MUX3 MUX2 MUX1 : Selects 1.1V (VBG)
ADMUX = bit (REFS0) | bit (MUX3) | bit (MUX2) | bit (MUX1);
ADCSRA |= bit( ADSC ); // start conversion
while (ADCSRA & bit (ADSC))
{ } // wait for conversion to complete
// int results = (((InternalReferenceVoltage * 1024) / ADC) + 5) / 10;
byte results = 32767*5-163800;
return results;
} // end of getBandgap

32767*5=163,835....-163800=35 so the result should be 35
even that prints correctly EVEN if it is only a byte

My point is that from what we see here is that you can use large number even larger than the capacity of the declared variable and it wont overflow AS LONG as the end result is less than the space of that given variable.

Try it!

Thanks

I just cleaned things up for you

void setup() {

Serial.begin(115200);

}

void loop() {
byte result=1062*1024-1087400;//result will be 1,087,488-1,087,400=88
Serial.println(result);//I GOT 88 EVEN IF THIS IS JUST A byte
delay(100);
}

Why do I get an accurate result with this

void setup() {

Serial.begin(115200);

}

void loop() {
byte result= (((32770 * 1024) / 32770) + 5) / 10;//
Serial.println(result);//I GOT 88 EVEN IF THIS IS JUST A byte
delay(100);
}

but not with this?

int results = (((1062 * 1024) / ADC) + 5) / 10;

32770 force the arithmetic to 'long'. That whole calculation is done (at compile time) as a 'long'. It just so happens that the answer fits in a byte.

All constants in the second equation fit into a (16-bit) 'int'. So, all calculations are done as 'int'. 1062*1024 overflows an 'int'.

PS -- Before posting again, learn how to properly post code using CODE TAGS!!!.

That ahaah moment!!
So you are saying that if the "written" values are within the..say byte range but somewhere along the calculation the value exceeded the overflow limit of byte the result will be wrong even if the true result fits into .. say byte?

But in my example I had a written value more than int so the equation space was automatically bumped up to long by the compiler. Is that correct?

P.s. I had trouble using "bold" in the code tags. I guess I'm not supposed to hit the bold button while writing in code tags. Will use from now on. Sorry.

ShmuelGlick:
Is that correct?

More or less. But I don't think compiler arithmetic is ever computed as a byte. Default is int.

More or less :slight_smile:
. I like that

>||<

Anyway. What I'm thinking is that since

   int results = (((InternalReferenceVoltage* 1024) / ADC) + 5) / 10;
   return results;
  } // end of getBandgap

The ADC part of the equation is not given and therefore not predictable. This is why the compiler does not bump it up to a long And that is the reason you have to declare

const long InternalReferenceVoltage = 1062;

Seems right?

gfvalvo:
Default is int.

Correct.

gfvalvo:
But I don't think compiler arithmetic is ever computed as a byte.

Incorrect. But a great deal of typecasting is required to force the compiler's hand.

Integer constants (nnnnnnn) are 'int' unless outside the allowed range for 'int', then promoted to 'long'.
Unsigned integer constants (nnnnnnnU) are unsigned int unless outside the range for unsigned int, then promoted to unsigned long.

Even if you cast both sides of an operator to 'byte' the operation will be done in 'int'.

  Serial.println(100 * 10);     // 1000 Promoted to 'int'
  Serial.println((byte)100 * (byte)10); // 1000 Promoted to 'int' despite casting
  Serial.println(10000 * 10);   // -31702 Integer overflow
  Serial.println(32767 * 10);   // -10 Integer overflow
  Serial.println(32768 * 10);   // 327680 Promoted to 'long'
  Serial.println(32768U * 10);  // 0 unsigned int overflow WITH NO WARNING
  Serial.println(65535U * 10);  // 65526 unsigned int overflow WITH NO WARNING
  Serial.println(65536U * 10);  // 655360 Promoted to 'unsigned long'
  Serial.println(100000 * 10);  // 1000000 Promoted to 'long'

Turning up warnings will get you the appropriate warning messages for int, but not for unsigned int:

sketch_jul13a.ino: In function 'void setup()':
sketch_jul13a.ino:7:24: warning: integer overflow in expression [-Woverflow]
   Serial.println(10000 * 10); // Integer overflow
                        ^
sketch_jul13a.ino:8:24: warning: integer overflow in expression [-Woverflow]
   Serial.println(32767 * 10); // Integer overflow
                        ^

johnwasser:
Even if you cast both sides of an operator to 'byte' the operation will be done in 'int'.

Including one more typecast coerces the compiler into producing code that does the operation using 8-bit arithmetic.

Comparing the code size / generated code by adjusting the comment shows the effect...

void setup(void)
{
  Serial.begin( 250000 );
} 

void loop(void)
{
  static byte lft;
  static byte rgt;
  ++lft;
  ++rgt;

  // Serial.println((byte)(lft * rgt));
  Serial.println((lft * rgt));
}

Got it. Will test. Thanks everybody!