### Author Topic: rprintf not giving me expected results  (Read 2748 times)

0 Members and 1 Guest are viewing this topic.

• Supreme Robot
• Posts: 11,703
##### rprintf not giving me expected results
« on: October 06, 2010, 04:16:33 PM »
I'm going crazy with rprintf here . . . this code:

Code: [Select]
`TICK_COUNT b;ACCEL_TYPE a;a=-599;b=17897;rprintf("%d %d %ld\n",a,b,a*(b/1000000));rprintfFloat(8,a*(b/1000000));`
prints out this data:
-599 17897 4
+0.000000

. . . but that doesn't make sense to me!

So I change order of operations to this, but it's still giving me unexpected outputs. Playing around with type casting didn't seem to fix stuff, assuming I did it right . . .

Code: [Select]
`a=-679;b=15428;rprintf("%d %d %ld\n",a,b,(a*b)1000000));rprintfFloat(8,(a*b)/1000000));`
prints out this:
-679 15428  4
+4106.0

The actual result of a*b/1000000, according to google calculator, is around -10 to -13, depending on a and b. What noob mistake am I making?

edit: fixed typo
« Last Edit: October 07, 2010, 03:36:46 PM by Admin »

#### KurtEck

• Robot Overlord
• Posts: 217
##### Re: rprintf not giving me expected results
« Reply #1 on: October 06, 2010, 06:37:16 PM »
The first one makes sense to me.  As you are doing fixed point math.
So b divided by anything greater than the value of b will give you a value of 0 which multiplied by anything will give you a value of 0.

I have not taken time yet to figure out your second half.  But I am pretty sure it has to do with what number system each calculation is being done at and if that overflows the registers.  It also does not help one of your variables is signed and the other is unsigned.  If it were me I would probably try casting the values while doing the math.  Maybe something like:( ((int32)a)*((int32)b)/1000000L

This is probably overkill.  Also I show your divide constant as a long.  I had to do some of this stuff when I converted the phoenix code that runs in Basic on a Basic Atom Pro to C as the basic did all of it's math as 32 bits...

Kurt

• Supreme Robot
• Posts: 11,703
##### Re: rprintf not giving me expected results
« Reply #2 on: October 07, 2010, 08:13:49 AM »
If it were me I would probably try casting the values while doing the math.  Maybe something like:( ((int32)a)*((int32)b)/1000000
Yea, this is one of the first things I tried yesterday - but no effect

#### knossos

• Robot Overlord
• Posts: 278
##### Re: rprintf not giving me expected results
« Reply #3 on: October 07, 2010, 08:43:11 AM »
Have you tried breaking it up into to halves to see which part of the formula isn't performing as expected.  For example:

Code: [Select]
`TICK_COUNT uint32 b;ACCEL_TYPE int16 a;int32 answer;a=-599;b=17897;answer=a*b;rprintf("%d\n",answer);rprintfFloat(8,answer/1000000);`
"Never regret thy fall,
O Icarus of the fearless flight
For the greatest tragedy of them all
Is never to feel the burning light."

— Oscar Wilde

#### KurtEck

• Robot Overlord
• Posts: 217
##### Re: rprintf not giving me expected results
« Reply #4 on: October 07, 2010, 08:47:09 AM »
I was just going to suggest something similar to what knossos mentioned.  If that did not work I would suggest trying something like he said be then trying:

Kurt

• Supreme Robot
• Posts: 11,703
##### Re: rprintf not giving me expected results
« Reply #5 on: October 07, 2010, 03:36:25 PM »
I've mostly figured it out . . .

this doesn't work:
Code: [Select]
`rprintf("%d %d %ld\n",a,b,a*(b/1000000));`
this does work:
Code: [Select]
`rprintf("%d %d\n",a,b);rprintf("%ld",a*(b/1000000));`
No idea why . . .

And changing ACCEL_TYPE for the accelerometer data to int16_t fixed the rest. I always thought ACCEL_TYPE *was* int16_t, but perhaps not? Can't seem to find it in the Webbot manual . . .

#### Webbot

• Expert Roboticist
• Supreme Robot
• Posts: 2,165
##### Re: rprintf not giving me expected results
« Reply #6 on: October 07, 2010, 04:33:06 PM »
Welcome to all that is bad, (or good if you understand whats going on), about C/C++ and most other languages.
This entire thread has nothing to do with WebbotLib or rprintf - its ALL about how C works.

The WebbotLib 'rprintf' command is identical to the standard C 'printf' routine in that it takes a variable number of parameters. The first parameter is the 'format string' showing how to display the answer. The remaining parameters are the values to be used in the format string.
The format string can contain things like:-
%s - to display a string
%d - to show a signed 16 bit (int16_t) number
%u - to show an unsigned 16 bit (uint16_t) number
%ld - to show a signed 32 bit (int32_t) number

Given the format strings you have used then the additional parameters should contain data which matches the data type from the format string.

You know this. The C language syntax document knows this. But unfortunately all C compilers have no idea that this is the case. As far as the compiler is concerned the format string is just that - its just a string. So the compiler has no way to check the datatypes in the format string against the other parameters which represent the values to be substituted.

As a simple example - the following is totally allowed by the compiler:
int16_t num = 65;
rprintf("Text =%s\n", num);
This will compile without any errors and you may expect it to output 'Text =65' but you would be very wrong.
It will output complete junk. The format string contains a %s meaning it should be replaced by the string given in the arguments. But the only other argument is 'num' which is an integer number and not a string. Since 65 is the ASCII value for 'A' then it will probably, if you are lucky, show 'Text =A' but, if you are unlucky' then this may be proceeded by all sorts of gubbins.

So lets take a look at one of admins examples:-
Code: [Select]
`uint32_t b = 17897;int16_T a = -599;rprintf("%d %d %ld\n",a,b,a*(b/1000000));`
The format string shows that it expects:
- an int16_t
- another int16_t
- an int32_t
But the actual parameters passed in are:
- 'a' an int16_t
- 'b' an uint32_t
- 'a*(b/1000000)' hard to say but since every element is an integer - the largest being a 32 bit number - then will probably be an int32_t

The result is that it prints out this data:
-599 17897 4
which Admin 'thinks' is wrong. Lets go through it by comparing the info shown above for what the 'format string' has been asked to do vs the actual parameter it has been passed to use.
1. Format string has '%d' ie an int16_t and it has been passed 'a' which is an int16_t and so outputs the correct answers '-599'
2. Format string has '%d' ie an int16_t and it has been passed 'b' which is an uint32_t. So now it will start outputing the wrong data.
3. Since the previous entry has been messed up then all remaining parameters will also be messed up.

Thats why the third value comes out as 4 rather than 0 - its messed up because of the mismatch on the previous values format string vs the data its been given.

So one way to fix it is force the parameters to match the types specified in the format string by using a cast. ie
rprintf("%d %d %ld\n",(int16_t)a, (int16_t)b, (int32_t)(a* (b/1000000) ) );

This will now output the last value as '0' rather than the erroneous '4'.
Admin tried to do this by having this as a seperate line of code which also outputs '0':-
Code: [Select]
`rprintfFloat(8,a*(b/1000000));`
The next question admin has is why does that last value come out as 0?
Well a=-599 and b=17897.
These are both whole numbers (integers).
The first step is (b/1000000) where b is an integer and 1000000 is an integer so the result (0.017897) as an integer is 0. Multiply by 'a' and the answer is still 0.
Since the rprintfFloat function expects a 'float' value then it will convert the value to a 'float' before printing. ie it converts the integer value '0' to the float value '0.000000'.

Code: [Select]
`rprintfFloat(8,(a*b)/1000000);`a * b = -10,720,303
div by 1000000 = -10
Converted to a float is -10.00000
So this will output -10.00000

So now we are getting closer but we are still seeing a whole number as the answer.
The 'fix' is to let the C compiler know that we are using floating point numbers inside the formula. ie
Code: [Select]
`rprintfFloat(8,(a*b)/1000000.0);`By adding the '.0' on the end then we are specifying a floating point number and not an integer
or
Code: [Select]
`rprintfFloat(8,(a*b)/1000000f);`By adding the 'f' at the end then we are saying its a floating point number.

So now we have (int * int) / (float) and so the answer will be a float rather than an integer
a * b = -10,720,303
div by 1000000.0 = -10.720303
Converted to a float is -10.720303
So this will output -10.720303

--- Update --

Code: [Select]
`rprintf("%d %d\n",a,b);rprintf("%ld",a*(b/1000000));`Seems to work but doesn't know why.

Well the reason is that he has split the rprintf into two - choosing the place where his format string was messing everything up.

Hopefully the discussion above will describe why it now works (but is actually still bad code as its fixed the output but not the problem)

Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk

• Supreme Robot
• Posts: 11,703
##### Re: rprintf not giving me expected results
« Reply #7 on: October 08, 2010, 09:24:33 AM »
Before I continue, I just want to say that I simplified my example in this thread to make it easy for anyone to understand and help debug it. There were quite complex calculations going on all over the place, with many variables dependent on each other. It was really difficult to figure out if the variables were saving data wrong, the calculations were wrong, or the rprintf was just outputting the data wrong . . . in the end, it turned out to be all three, making debugging a huge pain

Now knowing the root problems, its obvious I oversimplified the example here a bit too much.

Quote
3. Since the previous entry has been messed up then all remaining parameters will also be messed up.
That explains it! I wasn't sure how rprintf works . . . I assumed only 'messed up' values would get messed up, and not anything following. From now on I'll just break up my rprintf statements to help narrow done the mistakes.

Quote
So one way to fix it is force the parameters to match the types specified in the format string by using a cast. ie
rprintf("%d %d %ld\n",(int16_t)a, (int16_t)b, (int32_t)(a* (b/1000000) ) );
In the end, this is almost exactly what I ended up doing. This whole experience was a much needed lesson in properly casting variables . . .

Webbot, in your WebbotLib manual, can you state which variable type each %d,%ld,%s, etc. expects in the rprintf section? (page 93 of v1.26)  I think it'll help others avoid this issue.

#### knossos

• Robot Overlord
• Posts: 278
##### Re: rprintf not giving me expected results
« Reply #8 on: October 08, 2010, 12:03:45 PM »
Lol, I think we all knew you simplified the example  .  Yeah printf was kind of a duh moment for me too.  Should have realized it myself before my response but I was at work with my mind on other things .  But its always good to break down complex calculations and outputs into as many steps as possible to weed out exactly where the problem lies.
"Never regret thy fall,
O Icarus of the fearless flight
For the greatest tragedy of them all
Is never to feel the burning light."

— Oscar Wilde

#### Webbot

• Expert Roboticist
• Supreme Robot
• Posts: 2,165
##### Re: rprintf not giving me expected results
« Reply #9 on: October 08, 2010, 12:46:58 PM »
Webbot, in your WebbotLib manual, can you state which variable type each %d,%ld,%s, etc. expects in the rprintf section? (page 93 of v1.26)  I think it'll help others avoid this issue.
Will do
Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk

• Supreme Robot
• Posts: 11,703
##### Re: rprintf not giving me expected results
« Reply #10 on: October 11, 2010, 04:01:16 PM »
Actually, while your at it, could you also define the *_TYPE type variables in the manual.

Sometimes I need to do operations on this variables, or rprintf them out, and I'm just guessing the types when I do.

For example, is ENCODER_TYPE a int64_t, or just a int32_t?

#### Webbot

• Expert Roboticist
• Supreme Robot
• Posts: 2,165
##### Re: rprintf not giving me expected results
« Reply #11 on: October 11, 2010, 06:33:06 PM »
The easiest thing to do is look at their definition in the library.

Most sensors are grouped into a folder: eg Sensors/Distance.
That folder has a file of the format _xxxxx_common.h ie _distance_common.h
Open that up and you will see the #define for the DISTANCE_TYPE

equally ENCODER_TYPE can be found in Sensors/Encoder/_encoder_common.h

etc

Of course if you are using a decent IDE, like Eclipse, you can just highlight the datatype and press F3 and it will open up the correct file at the correct line number of where it is defined. Shame that AVRStudio is just a text editor. But hey ho.

Webbot Home: http://webbot.org.uk/
WebbotLib online docs: http://webbot.org.uk/WebbotLibDocs
If your in the neighbourhood: http://www.hovinghamspa.co.uk