|
|
View previous topic :: View next topic |
Author |
Message |
castek
Joined: 12 Jul 2012 Posts: 14
|
CCS math operation problems |
Posted: Sat Oct 13, 2012 8:20 am |
|
|
Hello everyone,
First of all:
My ver. is 4.130 PCD, and dspic33FJ32MC204
I´m trying to do some test calculations, first tried with fixed point calculations (_fixed(n)).
So my code is:
Code: |
unsigned int16 _fixed(2) ind1=4.12, ind2=2.23, ad, mul, div;
ad=ind1+ind2;
mul=ind1*ind2;
div=ind1/ind2;
printf("ad %w, mul %w, div %w", ad, mul, div);
|
But get:
ad=6.35 OK
mul=5.00 BAD
div=0.01 BAD
What´s wrong??
also tried with float,
Code: |
#include <float.h>
float ind1=4.12, ind2=2.23, ad, mul, div;
ad=ind1+ind2;
mul=(float)ind1*ind2;
div=(float)ind1/ind2;
printf("ad %f, mul %f, div %f", ad, mul, div);
|
and get:
ad=6.34 OK
mul=9.18 FAIR
div=1.84 OK
If I do same (float maths) for others value for ind1 and ind2: for example:
ind1=34.12 and ind2=2.23
I get:
ad=T.34 (Damn What!?)
mul=I.08
div=?.30
(I wrote literally what appears)
What I'm doing wrong??
I would like to use _fixed(n) because I know its more efficient, but maybe I don't know how to use it properly or there are some bugs left to be fixed. What should I do?
Thank you !! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19568
|
|
Posted: Sat Oct 13, 2012 9:07 am |
|
|
mul, and div, are compiler reserved names.....
Best Wishes |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sat Oct 13, 2012 10:10 am |
|
|
I wonder which operation you expect to be performed for the fixed point multiply and division and why, based
on which CCS document? There's no description of fixed point operation in the CCS manual, except for the
definition of _fixed(n) under types.
Although the assembly code is considerably blown up compared to regular integer multiply and division,
it doesn't give correctly scaled fixed point numbers as you apparently expect. The division result is the same
as if the numbers are simply divided without scaling, the same for the multiply, but only if the result is within
the 8-Bit boundary.
e.g. (for PCH V4.135)
1.00 * 0.02 = 2.00
1.00 / 0.02 = 0.50
In your example, the multiply result exceeds the 16-Bit range, but also outside the 8-Bit range, results are
different. But never as expected.
At first sight, it's just another CCS "soon come" feature |
|
|
castek
Joined: 12 Jul 2012 Posts: 14
|
|
Posted: Sat Oct 13, 2012 11:16 am |
|
|
It seems there are just two ways:
One way is using float point, but this seems not to be the right way. Too slow. However, why float point does not work OK and feedback me strange symbols like ?, R, T.. etc Is it a calculus problem or a representing problem?
The right way is to build me my own function to add and multiply in fixed point, I will work on that... Has anyone tried to work on fixed point and have some resources available?? |
|
|
castek
Joined: 12 Jul 2012 Posts: 14
|
|
Posted: Sat Oct 13, 2012 12:19 pm |
|
|
This is a fixed point function for multiplications.
Code: |
int16 mul(int16 ind1, int16 ind1_fx, int16 ind2, int16 ind2_fx, int16& res_fx)
{
volatile unsigned int16 res;
volatile unsigned int32 res1;
res1=_mul(ind1,ind2);
if(res1<65535)
;
else if(res1<655350)
res1=res1/10;
else if(res1<6553500)
res1=res1/100;
else if(res1>6553500)
res1=res1/1000;
res_fx=ind1_fx+ind2_fx;
res=(int16)res1;
return res;
} |
Where res is result, res_fx is fixed point location... ind1 is first operator and ind2 is second operator... ind1_fx and ind2_fx are first and second operators fixed point location.
Problem is when code tries to divide a number like res1=99999999/1000 the answer res is something like 127 !?
Other cases works ok, scaling to 10 or 100 is OK, but 1000 and more does not work. Its just a division between an int32 and constant 1000.
Whats wrong, me or PCD??
Rgds. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Oct 13, 2012 2:05 pm |
|
|
Quote: |
Problem is when code tries to divide a number like res1=99999999/1000
the answer res is something like 127 !?
|
I don't have the PCD compiler so I can't offer help on bugs, but my
advice is, if you want help from people who do have the compiler,
then post a short test program that shows your problem.
For example, I made this program for the 18F4520 and ran it in MPLAB
simulator and it works OK. Here's the output:
Test program:
Code: |
#include <18F4520.h>
#fuses INTRC_IO,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
//======================================
void main(void)
{
int32 res1;
res1 = 99999999;
res1 /= 1000;
printf("res1 = %lu \r", res1);
while(1);
}
|
Make a complete, testable program very similar to that one. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Oct 14, 2012 2:18 am |
|
|
I didn't notice that the original post was referring to PCD. Two additional comments:
float is working correctly both with PCH and PCD. I can't reproduce your results in this regard.
I still don't understand the idea behind the CCS _fixed operations. With PCD, it's clearer what the compiler
does, but I don't see why.
As mentioned, there's an 16-Bit overflow problem involved with the original multiply example.
Thus I changed the b value.
a=4.12; // stores 411 (!!!)
b=1.13; // stores 113
c=a*b; // result 464.00
d=a/b; // result 0.03
Interestingly, 46400 is not the product of 411 and 113.
It's 411*113*100/100
If you are interested in the details, here's the assembly listing.
Code: | .............................. a=4.12;
00E28: MOV #19B,W4 : W4 = 19B
00E2A: MOV W4,92A : [92A] = W4
.............................. b=1.13;
00E2C: MOV #71,W4 : W4 = 71
00E2E: MOV W4,92C : [92C] = W4
.............................. c=a*b;
00E30: MOV 92A,W4 : W4 = [92A]
00E32: MOV 92C,W3 : W3 = [92C]
00E34: MUL.UU W4,W3,W0 : W1:W0 = W4 * W3
00E36: MOV W0,W5 : W5 = W0
00E38: MOV W5,W4 : W4 = W5
00E3A: MOV #64,W3 : W3 = 64
00E3C: REPEAT #11 : Repeat next instruction (11 + 1) times
00E3E: DIV.U W4,W3 : W0 = W4/W3 :: W1 = W4 % W3
00E40: MOV #64,W4 : W4 = 64
00E42: MUL.UU W4,W0,W0 : W1:W0 = W4 * W0
00E44: MOV W0,92E : [92E] = W0 |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19568
|
|
Posted: Sun Oct 14, 2012 1:30 pm |
|
|
As an 'interesting', 4.137, refuses to compile if you try to use the _fixed() syntax.
It is worth perhaps noting that CCS has an 'example' of doing fixed arithmetic, and avoids this ability entirely, doing it themselves.
On castek's attempt at DIY, this seems fundamentally flawed. Of course it'll go wrong with 99999999/1000, the values are only int16 for the incoming numbers.
Best Wishes |
|
|
castek
Joined: 12 Jul 2012 Posts: 14
|
|
Posted: Mon Oct 15, 2012 5:43 am |
|
|
ok..
I just want to multiply unsigned int16 5000 * unsigned int16 5000 = unsigned int32 25000000, and then divide it per 1000 so I get unsigned int32 25000 so I can store in a unsigned int16 without overflows..
seams easy:
unsigned int16 ind1=5000;
unsigned int16 ind1=5000;
unsigned int32 res32;
unsigned int16 res16;
res32=_mul(ind1,ind2);
res32=res32/1000;
res16=res32;
What´s wrong? How can I do it?
¿¿How can I do it?? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19568
|
|
Posted: Mon Oct 15, 2012 8:32 am |
|
|
First, you don't need the 32bit value anywhere.
Code: |
unsigned int16 ind1=5000;
unsigned int16 ind2=5000;
unsigned int16 res16;
res16 = (_mul(ind1,ind2)/1000);
|
The '_mul' function, called with two int16 values, generates an int32 result. This then merrily divides by 1000 using int32 maths, and the result is directly converted to int16.
The traditional way to do this which involved slightly more time, is to use a cast:
Code: |
unsigned int16 ind1=5000;
unsigned int16 ind2=5000;
unsigned int16 res16;
res16 = ((int32)ind1*ind2)/1000;
|
Which then uses int32 maths (the cast forces this), and produces a 16bit result.
Both correctly give a 25000 result for me, with the former saving 56 instructions.
Best Wishes |
|
|
castek
Joined: 12 Jul 2012 Posts: 14
|
|
Posted: Mon Oct 15, 2012 9:07 am |
|
|
I´ve executed your code and res16=511
When I use ind1=500 and ind2=500, and divide per 1000 result is 3, if I divide per 100 result is 2500 and if I divide per 10 result is 25000.
Something does not work on PCD... Do you use PCD compiler ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19568
|
|
Posted: Mon Oct 15, 2012 9:21 am |
|
|
Yes, I compiled that for your chip with PCD, and for both calculations the result was correct.
Only difference, I haven't got version 4.130, had to use 4.134, and 4.137. Both gave correct results.
Now, I do remember a thread here about maths problems with PCD a little while ago, which would have been about when 4.130 was launched....
Best Wishes |
|
|
castek
Joined: 12 Jul 2012 Posts: 14
|
|
Posted: Mon Oct 15, 2012 2:16 pm |
|
|
I compiled the same code with PCD 4.134 but got same wrong result... this is quite weird !! (I have updated to 4.134)
Code: |
unsigned int16 ind1=5000;
unsigned int16 ind2=5000;
unsigned int16 res16;
unsigned int16 div=1000;
res16 = _mul(ind1,ind2)/div;
printf(LCD_PUTC, "\fA %u B %u \n res= %u", ind1, ind2,res16);
|
maybe problem is in printf !?
Result for res16 is 511... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Mon Oct 15, 2012 4:51 pm |
|
|
just for giggles, try %lu instead of %u and see if anything changes. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|