3021Views26Replies

# Two questions: 1. How do I calculate a "sign" with Arduino? 2. I have difficulties with fractions. Answered

Since these are two questions in one go, I'll be rewarding a patch!!!

Question 1
How do I calculate the sign of a number?
e.g. Sign(-3)=-1
e.g. Sign(5)=1

I could use an equation like: (-3)/(sqrt((-3)*(-3))) but that would be time consuming. Is there a function avalable?

Question 2
Consider the following program

int Xcoord[]={12,17,23,25,22,29,33,32,35};
int Ycoord[]={15,13,16,20,23,26,22,19,15};
int xCount = 9;
int x;
int y;
int a;
int xx;
int yy;
float SlopePower2;

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

void loop() {
for (int a = 1; a < xCount; a++)
{
int xx=Xcoord[a-1];
int yy=Ycoord[a-1];
int x=Xcoord[a];
int y=Ycoord[a];

SlopePower2=((y-yy)/(x-xx))*((y-yy)/(x-xx)) ;

Serial.print("SlopePower2 =");
Serial.print(SlopePower2);
Serial.println();
delay(5000);
}
}
//end

An Array is used to read numbers (this works fine).Then the power of the slope is calculated. Sometimes this number is larger than 1 (then the calculation works fine). However when the calculated value is between 0 and 1 ( a fraction thus)  it is rounded off to either 0 or 1 (although I have assigned it as a "float"). Why?

Tags:

## Discussions

What are you ACTUALLY trying to do ? Maybe there is a better algorithm

Steve

That's TOP SECRET! :-)
(I'm trying to build a robot for the contest).
It gets part of its input from a set of arrays X and Y (what I showed is part of the entire program). With this it has to calculate the slope and the distance between two points (x and y).
slope=dy/dx
distance=sqrt(dy*dy+dx*dx)
These are pretty basic equations, I don't think there is a alternative.

In the loop x and y are taken from the array's. Then dx and dy are calculated, then the slope and the distance are calculated (and some other stuff).
Would it be faster to to do the following?
In the setup() part of the program, quickly read the entire X and Y array and then fill a new Array with all the dx's, fill a new a Array with all the dy's, fill a new Array with all the new dy/dx.

In this way a large part of the calculation is kept out of the Loop(), making it faster (becaus in the Loop() only values of an Array have to be read instead of calculated).

Does this make sense? If so, how do I fill an Array that is a result of a calculation.

There are different methods for calculating slope, slightly, ones that don't involve a division. Look up "Bressenham's algorithm" for some inspiration.

Do you need the sqrt calculation ? You could just work in distance squared units.

Steve

I'll look into this Bressenham's Algoritm...
Do I need sqrt? I use Pythagoras to calculate the "long side"of a triangle (sorry for my English here). I could switch to Sin/Cos or Tan type calculations, but would this make it easier or faster?
Are you thinking of something else?

I was trained as a Petroleum Engineer and as I consequence, I try to solve all my problems with a pipe wrench. This Arduino stuff is pretty new to me.
You have pointed out an algorithm that's been around since the sixties and I never heared of it. That's humbling (thanks!).
I'll have to study it closer though.

What about the idea of reading out the arrays in the Setup() phase. Would that help / work?

....and I work in instruments for measuring Lubricants. You're not with Shell are you ?

You could look at the potential values from your distance calculations, and use a look-up table.

Ask yourself (and tell me !!) what the practical resolution you need from your distance measurement is.

There are all SORTS of clever tricks you can do in an embedded system that aren't taught anywhere.

Steve

No, not with Shell. Moreover, nowadays I work in the field of renewable energy (biomass).

Practical resolution? If the Array is in cm, then I guess I need an accuracy of 2mm.

I'm very much interested in your ideas, but they are a bit "intimidating" as well. I have an idea for which I need to figure out a lot of stuff as it is:
1. The routines (currently discussing).
2. Getting the servos to work (in combination with the routine).
3. Building the mechanical parts.

If I introduce other algorithms (which I currently do not master) then my project becomes more complex. Maybe I should take the project as far as possible with "classic" algorithms and then come back to you for "the need for speed"?
We could eventually turn it into a collaboration if required...

2mm in total range of.... ?

100 cm ?

Personally, I would write a simulator program to evaluate my routines, before I built the rest of the machine a.) Because you can't break a program. and b.) The hardware may not match your final software !

Steve

Well, I'm more or less doing so...
I have done the calculations and graphs in Excell,
then I compare it to the output of the Arduino (by using a lot of Serial.print commands).

if abs(x) = x then
sign = 1
else
sign = -1
end if

Hey! We all got it wrong. Sign(0) == 0. And I just stumbled across an awesomely compact representation:

sign(double x) { return ((x>0)-(x<0)); }

where you take the numeric values of the bools, instead of conditionals.

This method performs integer math on values returned from boolean operators which in C always returns 1 for True and 0 for False.

I'm old-school and got too many other computer languages on the brain.  In other languages sometimes FALSE is 0 and TRUE is Not 0 and not necessarily 1.

I didn't realise that in all implementations of C, boolean operators returning true is always return 1.

Thank you for improving my understanding!

Best Wishes

You're welcome! In C (and C++) an operation returning a boolean value has true => 1, false => 0. However, the converse is more general: an operation returning an _integer_ value may be interpreted as boolean with 0 => false, any non-zero => true.

This is why you can write null-pointer checks in the form "if (!pointer) got-a-null-here;" Only the zero pointer will resolve that expression to true.

In FORTRAN, things are different, FALSE=0 still, but TRUE=-1.

That adds a function call, which is CPU-expensive (it's a potential long jump). That's why I wrote the direct "if (x<0)" condition.

My first answer to (1) was not correct. I don't feel too badly about that, because Nacho and Steve got it wrong, too! The correct expression is

sign(x) = +1 for x>0, 0 for x==0, and -1 for x<0

(I ignored the middle case). Doing a Web search, I found a beautifully compact representation, which uses the boolean numeric values (true=1, false=0) to compute the result without conditionals
`int sign(double x) { return (x>0) - (x<0); }`

Ha, ha, ha. You guys are making it hard to select the best answer with all the mistakes!
No but seriously, the effort is highly appreciated and for one, Í didn't know the answer in the first place.

I was surprised by the extreme compact suggestion you made. I have never seen it in the "classic" text books. Is this a variation of some kind?

You won't find things like that in introductory textbooks, because it is likely to confuse students learning the language. What you're doing is relying on the internal representation of "bool" types as integral values, and implicit casts to do the arithmetic. The result is well-defined (and documented, for example, in K&R).

You will find a lot of that stuff in more advanced textbooks, generally in discussions of code optimization. That's also where you're likely to find some of the really obfuscatory tricks like using bit-shift operations for specialized arithmetic, the use of "register" variables, and so on.

Bah, Mine was only pseudocode, not C++. I write real programs in Pascal, and Fortran....

In Pascal

Sgn:=0;
IF number > 0 then sgn:=1
ELSE
if number <0 THEN sgn:=-1;

Besides, I didn't ignore the middle case, I decided to roll it into <0.....

Steve

:-) Yep; the initializer takes care of the zero case (but you didn't initialize in your original version :-).

No, but there were only two states >0 and <= 0.
So nothing stayed undefined :-)

Steve

1) Don't use an equation, since you'll have divide-by-zero problems. Just use the ternary operator:
`int sign(double x) { return x<0 ? -1 : 1; }`

2) Your slope comes back as an integer because all of its operands are integers. Look at K&R, Chapter 2 (I think). If you want to compute a floating point ratio, you need to cast the operands to float:
`SlopePower2 = float(y-yy)/float(x-xx);SlopePower2 *= SlopePower2;`

Note: Don't calculate the ratio twice; that's a waste of time. Also, take the declarations out of the loop; that's allocating extra and unused memory.

In addition, be sure to catch the x=xx case for undefined slope before any computations are performed.

We know that only Chuck Norris can divide by zero.  :-)

IEEE can divide by zero perfectly well. You'll get SlopePower2 = +Infinity or -Infinity depending on the sign of y-yy. If y-yy==0, then you get a NaN.

1.) IF number > 0 then sgn=1 ELSE if number <=0 sgn=-1

2.) You are dividing two integers in the maths, therefore the result is integer1 DIV integer2 and not /

Steve