|
|
View previous topic :: View next topic |
Author |
Message |
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: 19515
|
|
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: 19515
|
|
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: 19515
|
|
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: 1349
|
|
Posted: Mon Oct 15, 2012 4:51 pm |
|
|
just for giggles, try %lu instead of %u and see if anything changes. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Oct 16, 2012 1:02 am |
|
|
Could easily be a printf bug, I was watching the variable in a debugger.
Have just tried using sprintf, with 4.137, and %u, %lu (shouldn't be needed PCD treats an int as int16), and %d, all gave the same output of 25000.
Best Wishes |
|
|
castek
Joined: 12 Jul 2012 Posts: 14
|
|
Posted: Tue Oct 16, 2012 3:24 am |
|
|
I have changed but got same problem, result is still 511. How can I see the true value for res16?? I dont know if its a printf problem or a PCD math problem.
However I found a bad solution.
PCD gives a good result that way:
unsigned int16 ind1=5000;
unsigned int16 ind2=5000;
unsigned int16 res16;
unsigned int32 res32;
res32 = _mul(ind1,ind2)/100;
res32=res32/10;
res16=res32;
printf(LCD_PUTC, "\fA %Lu B %Lu \n res= %Lu", ind1, ind2, res16);
Dividing per 1000 does not work, but if I divide fist per 100 and then per 10 (which is the same as dividing per 1000), now it works.... Finally I think it´s a PCD problem
¿¿Did you tried it in PCD 4.134??
Last edited by castek on Tue Oct 16, 2012 4:29 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Tue Oct 16, 2012 4:27 am |
|
|
Depends what debugging tools you have got.
Free one, is MPLAB, and run it in MPSIM.
Is anything else being done, while this code is working?. I find it too 'odd' that it gives perfectly normal results for me. Something overrunning an area of memory, and corrupting a variable, or something happening in an interrupt, are obvious suspicions.
Best Wishes |
|
|
castek
Joined: 12 Jul 2012 Posts: 14
|
|
Posted: Tue Oct 16, 2012 5:14 am |
|
|
Well.. I´m printing the result in an LCD in proteus... maybe there´s the problem. I´m using PCD 4.134 same as you. However I´m downloading the demo version of PCD 4.137 to check... I´m getting crazy, dont know why I cant divide a number higher than 1000 without errors. The extrange thing is that I can divide per 100 but not per 1000... !?! |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9228 Location: Greensville,Ontario
|
|
Posted: Tue Oct 16, 2012 5:42 am |
|
|
PIC rule #0 : READ PIC101 !!
PIC rule #1 : GET RID OF PROTEUS !!
PIC rule #2 : ALWAYS OBEY rule #1 !!
PIC rule #3 : PROTEUS is full of bugs,errors, faulty DRCs |
|
|
|
|
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
|