CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

CCS math operation problems
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
castek



Joined: 12 Jul 2012
Posts: 14

View user's profile Send private message

CCS math operation problems
PostPosted: Sat Oct 13, 2012 8:20 am     Reply with quote

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: 19551

View user's profile Send private message

PostPosted: Sat Oct 13, 2012 9:07 am     Reply with quote

mul, and div, are compiler reserved names.....

Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Sat Oct 13, 2012 10:10 am     Reply with quote

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 Sad
castek



Joined: 12 Jul 2012
Posts: 14

View user's profile Send private message

PostPosted: Sat Oct 13, 2012 11:16 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Oct 13, 2012 12:19 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Oct 13, 2012 2:05 pm     Reply with quote

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:
Quote:

res1 = 99999

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

View user's profile Send private message

PostPosted: Sun Oct 14, 2012 2:18 am     Reply with quote

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: 19551

View user's profile Send private message

PostPosted: Sun Oct 14, 2012 1:30 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 15, 2012 5:43 am     Reply with quote

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: 19551

View user's profile Send private message

PostPosted: Mon Oct 15, 2012 8:32 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 15, 2012 9:07 am     Reply with quote

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: 19551

View user's profile Send private message

PostPosted: Mon Oct 15, 2012 9:21 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 15, 2012 2:16 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 15, 2012 4:49 pm     Reply with quote

I don't have PCD, but this thread says that vs. 4.134 did have printf problems:
http://www.ccsinfo.com/forum/viewtopic.php?t=48569
jeremiah



Joined: 20 Jul 2010
Posts: 1357

View user's profile Send private message

PostPosted: Mon Oct 15, 2012 4:51 pm     Reply with quote

just for giggles, try %lu instead of %u and see if anything changes.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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