Too Much Math on One Line ?

I tried searching for the answer to this one on my own, but its such a vague question, i don't know what to search for...

Am i going to get messy results of i do something like this: (This is totally hypothetical, i just typed it up)

 float EEHypot = (sqrt((sq(VertDistJ3toEE) + sq(HorzDistJ3toEE)  + 100 ) / 2000 ) / 3.14) *

I have tried this previously and it didn't work until i broke it into smaller equations with more variables. i just don't understand how a microprocessor could screw up math i guess :/

The things you need to worry about: * Integer math truncating results when you think it's doing floating point math. Be sure you understand the rules for type promotion. * Floating point numbers are not exact - this can cause unexpected results when comparing them, particularly when you're converting them back into integers - if the floating point value is a hair lower than that integer (ie, 0.9999 instead of 1), it will get truncated, and come out as zero!

Try to avoid using floats when possible (they don't have hardware support, so mathematical operations with them are kinda bulky), watch out for type promotion behavior, and set an alarm in your brain to go off whenever you see a division symbol when working with integers, and of course, be careful when turning floats into integer datatypes.

How do i know when its doing integer math VS Floating point math?

What I'm doing requires me to be accurate to +/- .1mm at a distance of 150mm from a pivot, that is .03819 degree, or .00066666 radians

Now of course that kind of movement is about 30 pulses to my stepper driver, but i think the real issue is that arduinos trig functions return radians, i really did not think that my accuracy issues would be coming from the software side, i assumed the issue would be more hardware related, or speed related

one thing that i have going for me is I'm using arduino Due and that can compensate for my crappy coding skills

The compiler should handle it fine, and it will do exactly what you tell it to (integer math with integers, etc.)

To avoid integer vs float problems, make sure all of your costants are floating point (100.0 instead of 100, etc.)

Now, there is absolutely NO ADVANTAGE to writing your expression all on one line, and the chance that you will run into some inadvertent "order of operations" problem gets higher. And readability suffers at some point; you're probably much better off dividing it up into several lines...

Sparkyman: float EEHypot = (sqrt((sq(VertDistJ3toEE) + sq(HorzDistJ3toEE)  + 100 ) / 2000 ) / 3.14) *

Replace the "*" on the end with a ";" and it will compile (and run) just fine.

Westfw, are you saying that adding that changing this

From this: float VerticalCalc4 = VerticalCalc3 * 180 / Pi; // Convert that number back to degrees,

to this:

float VerticalCalc4 = VerticalCalc3 * 180.0 / Pi; // Convert that number back to degrees,

are you saying that adding .0 to a constant will change how Arduino does the math?

See this. https://www.arduino.cc/en/reference/float

Sparkyman: Westfw, are you saying that adding that changing this

From this: float VerticalCalc4 = VerticalCalc3 * 180 / Pi; // Convert that number back to degrees,

to this:

float VerticalCalc4 = VerticalCalc3 * 180.0 / Pi; // Convert that number back to degrees,

are you saying that adding .0 to a constant will change how Arduino does the math?

Yes you made need to add the ".0" in some circumstances.

The line: float VerticalCalc4 = VerticalCalc3 * 180 / Pi; is fine IF VerticalCalc3 is float. Otherwise you might need to change the 180 to 180.0 (depending on whether or not integer overflow is a problem here).

Note that even the divide Pi (presumably Pi is already float) on the end wont save you here, as C will simply use integer arithmetic while evaluating the right hand side of the expression (from left to right) UNTIL it is forced to promote to float.

So if VerticalCalc3 is float then no problems, it will evaluate the RHS in float from the get go. If however VerticalCalc3 is integer then C will start the evaluation and do the multiplication as an integer.

Well....

float x = 100/180;   // certainly wrong.  (0.0)
float x = 100.0/180.0;  // certainly right. (0.555556)
float x = y * 100/180;   // I'm not sure.  Might depend on type of y.  Might be wrong even if y is float.
float x = 3.14 * (100/180);  // not sure again.  parenthesis before or after type promotion?

Now on some of those, I could look up the rules, or ask stackoverflow. But I can also MAKE myself sure by including the decimal points everywhere, and that's a lot easier...

float x = y * 100/180;   // I'm not sure.  Might depend on type of y.  Might be wrong even if y is float.

Yep, depends on the type of y. The multiplication will be treated as if it were done first, even if the compiler optimises the expression.

float x = 3.14 * (100/180);  // not sure again.  parenthesis before or after type promotion?

Parenthesis first. This will always come out as zero.

Thanks for my help guys. Hopefully changing all of my numbers to number.0 will help my Robotic Arm trig be more accurate and get rid of the oddball glitchieness

Also will start separating my math out to separate lines and serial printing the results and double check that it's doing the math like I expect it to.

Maby it could be faster to do the trig in a Raspberry PI and communicate the results to the Arduino. I've never owned or programmed a raspberry pi so idk. I'm just looking for fluid movements, that's all.

The only problem with a complicated expression on Arduino can be due to the fact that the processor only has a small number of registers and the compiler may be unable to generate code for the whole expression because it runs out of free registers. It will generate this error:

unable to find a register to spill in class 'POINTER_REGS'

The solution is to break the expression into several statements, but there's no need to do this unless this error occurs. The other problems of int/float etc. can happen in a simple expression too.

Pete

Sparkyman: Thanks for my help guys. Hopefully changing all of my numbers to number.0 will help my Robotic Arm trig be more accurate and get rid of the oddball glitchieness

Also will start separating my math out to separate lines and serial printing the results and double check that it's doing the math like I expect it to.

Read Pete's reply above. If it really was due to there just being too many computations on a single line then it would probably be a different kind of error and error message.

Not the it hurts to limit line length and calculation depth per line. It can make your code easier to read and easier to debug, however I don't think it is the specific reason for the "spurious" results in your case.

If you want full float evaluation of an expression then, at an absolute maximum, all that is needed is at least one operand per binary operator ( '+' , '-' , '*' and particularly '/' ) that is either:

  • a float variable
  • another numeric variable typecast to float
  • a const float
  • a literal constant including a decimal point.

If you are totally confident about the precise order in which C evaluates your expression (I'm not, but some are more familiar with this than myself) then you may need less than outlined above. But at least one float per operator will definitely assure a fully float evaluation.