#define math is wrong by a factor of 10, what? how?

doing math to calculate the value of a #define is wrong when compared to a calculator, or when compared to doing math with a double variable.

Ive been chasing this issue for about 4 hours total, I finally got it fixed, but I'm still trying to figure out whats going on. would be nice to know so I can avoid it in the future.

This code:

#define Value1 152.4 * 3.14 // notice the lack of parentheses 
#define Value2 (8000.0/Value1)

#define Value1b (152.4 * 3.14) // added parentheses 
#define Value2b (8000.0/Value1b)

void setup()
{

  Serial.begin(115200);
  Serial.print("Value1:            "); Serial.println(Value1);
  Serial.print("Value2:  (Wrong)   "); Serial.println(Value2);
  Serial.println();
  Serial.print("What it should be: "); Serial.println(8000 / 478.78);
  Serial.println();
  Serial.println("Adding parentheses on the calc of the first value");
  Serial.println("doesnt change the first value");
  Serial.println("but fixes the second vaule");
  Serial.println();
  Serial.print("Value1b:            "); Serial.println(Value1b);
  Serial.print("Value2b:  (correct) "); Serial.println(Value2b);
}

void loop() {

}

will serial print this:

Value1:            478.54
Value2:  (Wrong)   164.83

What it should be: 16.71

Adding parentheses on the calc of the first value
doesnt change the first value
but fixes the second vaule

Value1b:            478.54
Value2b:  (correct) 16.72

and I can't seem to figure out why...

where is the error in my ways?

Edit: simplified code for readability

There's a big difference between this

#define wheelCircum wheeldiameter * pi // circumfrence in mm

and this

double wheelCircum2  = (wheeldiameter2 * pi); // circumfrence in mm

Pete

el_supremo: There's a big difference between this

#define wheelCircum wheeldiameter * pi // circumfrence in mm

and this

double wheelCircum2  = (wheeldiameter2 * pi); // circumfrence in mm

Pete

Sorry Pete, I was in the process of simplifying my post when you replied, the same issue can be observed, but now it can be observed without the use of a double

Use:

#define wheelCircum (wheeldiameter * pi) // circumfrence in mm

SP: circumference

The compiler is RIGHT and you are WRONG!

Look up

a. what the pre-processor does

b. operator precedence

Mark

Macros, aka #define, are a text replacement upon compile. There is no inherent checking done on your behalf.

define pi 3.14159265359

define wheeldiameter 152.4

define wheelCircum wheeldiameter * pi

define stepsPerRev 8000.0

All good.

define stepsPermm stepsPerRev/wheelCircum

gets replace with

define stepsPermm stepsPerRev/wheeldiameter * pi

Now do the math.

Change #define stepsPermm stepsPerRev/wheelCircum to #define stepsPermm (stepsPerRev/wheelCircum)

and the problem goes away.

#define Value1 152.4 * 3.14 // notice the lack of parentheses 
#define Value2 (8000.0/Value1)

#define Value1b (152.4 * 3.14) // added parentheses 
#define Value2b (8000.0/Value1b)

Look at how Value2 gets calculated in the two different ways, remember we do multiplication and division with equal priority going left to right. But note how the parenthesis changes the calculation.

Value2 == (8000.0 / 152.4 * 3.14) == 52.4934 * 3.14 == 164.83

Value2b == (8000.0 / (152.4 * 3.14)) == 8000.0 / 478.536 == 16.7

ah!

I thought the computer would see math, and do the math ASAP,

didn't realize that it literally just passes the buck with the equation and causes problems with order of operations.

This was actually really important for me to learn, I cant even imagine the length of the equations in some of my programs for values that don't even change after the compile.

Thanks for the help! :)

Sparkyman: ah!

I thought the computer would see math, and do the math ASAP,

didn't realize that it literally just passes the buck with the equation and causes problems with order of operations.

define is literally just a text based find and replace. And it happens before the code gets compiled. You can never go wrong with an extra set of parenthesis in a macro.

A / B * C

is not the same as

A / ( B * C ).

This is why I always use const rather than #define.

Serious question: is there ever a good reason to use #define instead of const?

is there ever a good reason to use #define instead of const?

You can do preprocessor magic like Stringification and symbol concatenation with #defines

You can use #define also to sobstituilte functions. For example I'm makeing my oun arrays library, and I everitime use the same arguments for function: char stringa[], byte lunghezza. I can made a macro, for example ANP char stringa, byte lunghezza and use it instead the repetition of this parameters. I can't use const because it is not a value.

Another think is that const make a variable and define no. If you have problems about memory a const or a #define can be different

Are you sure a const makes a variable? That is, that it takes any memory at run time?

Seems like the compiler would use the const in the same way it would use a simple #define - use the value to make code at compile tiem. It mightn't be necessary to have the value held in memory at all.

a7

This is one of the good examples why macro should be left in the C-era. C++ has safer alernatives for mot macro magic.

@Silente, const doesn't take memory in 99% of the time. Only if the compiler feels it can optimize to code a lot for example.

Also, ye you can do magic like that with macro's. But does it really get any more readable?

Also, you can use a struct as an alternative. Just pass a struct of a char * and a byte, done! Without trickery.

Of corse I can make and pass structures, bit I am writing this library for beginners, and a beginners doenn't know structures

septillion: C++ has safer alernatives for mot macro magic.

What is "mot macro magic"?

Sparkyman: This was actually really important for me to learn, I cant even imagine the length of the equations in some of my programs for values that don't even change after the compile.

Then you should be using variables with const types instead of defines. defines are not variables defines are macros (strings) and are not even seen by the compiler. defines are processed by the C preprocessor which runs before the compiler. The preprocessor does a simple string substitution into the source module where ever the macro is referenced. That modified source code module is handed to the compiler for compilation.

Whereas, when using a const variable, the compiler will pre calculate the value at compile time and assign it to the variable so that the pre-calculated value is used wherever the variable is later used in code.

--- bill

bperrybap: Whereas, when using a const variable, the compiler will pre calculate the value at compile time and assign it to the variable so that the pre-calculated value is used wherever the variable is later used in code.

Even if you have the compiler do the math, it is still a good idea to do the math yourself using a calculator so that you have an idea of about how big the number is going to be. This is especially useful if you are concerned about a number possibly overflowing a datatype. (For example, a number like 90000 will not fit in an int.)

odometer: Even if you have the compiler do the math, it is still a good idea to do the math yourself using a calculator so that you have an idea of about how big the number is going to be. This is especially useful if you are concerned about a number possibly overflowing a datatype. (For example, a number like 90000 will not fit in an int.)

It depends on the processor used as different Arduino boards use different processors which have different integer sizes. i.e. while 90,000 doesn't fit into an int on AVR (UNO/Mega) it does fit into an int on pic32 (chipkit), ARM (due, teensy3, stm32), and esp8266 based boards as well as several others.

--- bill