multiplication problem

Hi.
I am perhaps very new and this is perhaps a silly question :confused: but...
when I add these lines:

unsigned long valor = (4*10000);
Serial.println(valor);

I get the following result: 4294941760

Can you help me to get 40000?

Thanks in advance.

 unsigned long valor = (4UL*10000UL);

Thanks a million AWOL :slight_smile:

Not to hi-jack templas' thread, but how would one handle his issue if it were written like the following?

int x = 4;
int y = 10000;
int value = (x*y);

The only way I could get something similar to give the correct value was to write it like this.

int value = (4.0*10000.0);

Which did away with the x and y variables that I wanted to be able to change. I think (away from my pc) that I had the larger variables (y and value in this case) as "unsigned long".

int value = (x*y);Well, for a start, a sixteen bit int is never going to hold the value 40000.
Simply casting x and y to unsigned long would do your trick.

40,000 won't fit into a signed int. When you try to make it fit you get -25536 (0x9C40). When promoting a value the size changes first so when going from signed int to unsigned long int the first step is sign extension. The -25536 (0x9C40) becomes -25536L (0xFFFF9C40). Then that is changed from long int to unsigned long int and the resulting value is 4294941760UL.

If you make 'value' an int you get a different wrong answer: -25536.

1 Like

Thank you awol.

I guess the basic example I made using templas' numbers was too basic. The code I was messing with had no purpose other than learning. But it was something more like this.

int earlyTime = 0800; 
int lateTime = 1900;
unsigned long milliPerHour = (60 * 60 * 1000);
unsigned long timeDiffMilli = ((lateTime -
 earlyTime) * milliPerHour);

void setup(){
  Serial.begin(9600);
  Serial.println(timeDiffMilli); // prints 4290039296
  //1100 * minutes * seconds * milli
  unsigned long myMath = (1100.0*60.0*60.0*1000.0);
  Serial.println(myMath); // prints 3960000000

Didn't sleep well and it's early. So the math may be wrong. But I think the point is there. When I did a Serial.println(timeDiffMilli), I was getting some really weird numbers (as would probably be expected by someone familiar with the arduino language).

And my formula isn't quite right. Its calculating based on 1100 hours. Not 11. But, again, the point is there.
(forgot decimals 60.0) fixed.

int earlyTime = 0800;

Beware octal!
Edit: that should give an error.

unsigned long milliPerHour = (60UL * 60UL * 1000UL);

AWOL:

int earlyTime = 0800;

Beware octal!
Edit: that should give an error.

unsigned long milliPerHour = (60UL * 60UL * 1000UL);

It did. Like I said, it's early. Coffee hasn't kicked in. Forgot to edit that.

And using your edit works fine. I also, tried just using one "UL" in the milliPerHour and it worked too.

So, as long as one variable has the "UL", it keeps the whole calculation from getting, for lack of a better word, distorted?

So, as long as one variable has the "UL", it keeps the whole calculation from getting, for lack of a better word, distorted?

Not necessarily. The order of evaluation is left to right, so put the UL at the end of the first constant.

Try this:

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
Serial.println("starting");
Serial.println(1000*2000*1UL);
}

void loop() {
  // put your main code here, to run repeatedly:

}

jremington:
Not necessarily. The order of evaluation is left to right, so put the UL at the end of the first constant.

Try this:

void setup() {

// put your setup code here, to run once:
Serial.begin(9600);
Serial.println(“starting”);
Serial.println(100020001UL);
}

void loop() {
  // put your main code here, to run repeatedly:

}

Thank you for the clarification.

unsigned long valor = (4*10000);
Serial.println(valor);

I get the following result: 4294941760

Can you help me to get 40000?

//-------------------------------------------------------------------------------------------------------------------
@AWOL has fixed the result; it is genuinely appreciated. This approach goes perfectly in line with @aarg who always suggests to talk/write at the understanding level of the help seeker.

unsigned long valor = (4UL*10000UL);

//-------------------------------------------------------------------------------------------------------------------

The problem can also be solved in the following way:

unsigned int x = 4;
unsigned int y = 10000;
unsigned long valor = x*y;
Serial.println(valor);               //shows: 40000

//-------------------------------------------------------------------------------------------------------------------

The problem can’t be solved in the following way in spite of the fact that the variables x and y can accommodate the values 4 and 10000 respectively. The reason is explained in 2. below.

int x = 4;
int y = 10000;
unsigned long valor = x*y;
Serial.println(valor);               //shows: 4294941760

//-------------------------------------------------------------------------------------------------------------------

But, that’s not all! We need to accept that the value (4294941760) generated by the program/processor is correct; (!) although, it is not acceptable to us. We have clearly entered two positive values 4 and 10000. We want a positive result of 40000.

429491760 is an incorrect result (not wrong!) which can be corrected to get 40000. Or, we can analyse the program codes of the OP to find if he has made any mistake in the definition of variables!
//-------------------------------------------------------------------------------------------------------------------

@johnwasser (Post #5) has made a critical analysis to explore the reason for the generation of the incorrect result 429491760.
//-------------------------------------------------------------------------------------------------------------------

Being inspired by the analysis of @johnwasser (Post #5), I am making below an alternative analysis for the source of the generation of the incorrect result 429491760.

1. The OP has defined

unsigned long valor  = (4*10000);

Here is the main source of mistake! The integer constants (4, 10000) of the constant expression (4*10000) are taken by processor/compiler as belonging to int data type (by default) instead of unsigned int what has been in the mind of the OP.

According to Arduino Programming Reference Manual, an integer constant (in an constant expression) is taken as int data type (16-bit signed number: -32 768 to +32 767 inclusive).

2 So, the processor/compiler has found two variables:

int x1 = 4;
int y1 = 10000;

Naturally, the processor/compiler has performed a 16-bit signed multiplication; the expected result is 32-bit. However, because of the reduced range of the operands, the result has appeared as 0x9C40. What’s about the upper 16-bit? We will see it below!

Now, let me explain to you a little bit how 16-bit signed multiplication takes place in the 80x86 architecture before I show how 0x9C40 turned into an incorrect decimal 429491760 instead of correct decimal 40000.

In 80x86 architecture, the 16-bit mul instruction produces 32-bit result and stores them into <dx, ax> register-pair. If the result fits into lower register (ax), then the processor fills up the upper register (dx) with the copies of the MS-bit (MS-bit of 0x9C40 is 1) of the lower register. In the present case, the result fits well in the lower 16-bit (ax) register. Therefore, <dx, ax> will hold <1111 1111 1111 1111, 9C40 = FFFF9C40). This fact has also been explained by @johnwasser in Post #5.

3. The OP has declared valor as a 32-bit memory location. It is, in fact, the high level view of the <dx, ax> pair. In ATmega328, it is the cascading of four 8-bit wide memory/register locations. The lower 16-bit of valor will hold 0x9C40 (1001 1100 0100 000). The upper 16-bit of valor will hold the copies of the MS-bit of the its lower 16-bit. Therefore, the 32-bit content of valor is: 1111 1111 1111 1111 9C40 = FFFF9C40. This can also be proved by executing the following codes:

unsigned long valor = (4*10000);
unsigned long *ptr;
ptr = (unsigned long*)&valor;
unsigned long m = *ptr;
Serial.println(m, HEX);            //shows : FFFF9C40
Serial.prinln(m, DEC);             //shows: 429491760

//-------------------------------------------------------------------------------------------------------------------

Finally, the conclusion: we remain careful about the syntax and semantics rules of the Programming Language we are using to solve our problems. If we do so, the processor/compiler will always keep us happy!

Integer constants are not always taken by default as int. It is in constant expressions that they are.
For example, unsigned long foo = 1000000;is just as valid as

unsigned long foo = 1000000UL;

But you can't have

unsigned long foo = 1000 * 1000;

as discussed above

DangerToMyself:
I was getting some really weird numbers (as would probably be expected by someone familiar with the arduino language).

It is not about Arduino language. It is computer programing basics. Overflow can happen on 64bit system too, just with bigger numbers.

Integer constants are not always taken by default as int. It is in constant expressions that they are.

Great appreciation for the dissemination of this information. I note it down.