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 support@ccsinfo.com

math error - signed int16 and negative numbers

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

math error - signed int16 and negative numbers
PostPosted: Tue Feb 06, 2007 5:25 pm     Reply with quote

I spent most of the day trying to figure out why a program wouldn't give me correct results, and it all boiled down to one line giving incorrect results when a variable became negative. If a signed int16 variable is positive and is multiplied by 1440, the results are correct. If the variable becomes negative, the results are wrong.

Here is some output from the program below:

Code:
1. A = 3
2. B = 4320 // correct
1. A = 2
2. B = 2880 // correct
1. A = 1
2. B = 1440 // correct
1. A = 0
2. B = 0 // correct
1. A = -1
2. B = -1184 // what the ?
1. A = -2
2. B = -2624 // huh?
1. A = -3
2. B = -4064 // dammit!


PCWH version 3.236

Code:
#include <18F4580.h>
#device adc=8
#use delay(clock=20000000,RESTART_WDT)
#fuses HS, BROWNOUT, BORV46, PUT, STVREN, NOLVP
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

#define TX_BUFFER_SIZE 80

int8 tx_rd_index = 0, tx_wr_index = 0, tx_counter = 0;
unsigned int8 tx_buffer[TX_BUFFER_SIZE + 1];
signed int16 a, b;

#int_TBE
void TBE_isr(void) {
   if (tx_counter != 0) {
      putc(tx_buffer[tx_rd_index]);
      if (++tx_rd_index > TX_BUFFER_SIZE) {
         tx_rd_index = 0;
      }
      tx_counter--;
      if (tx_counter == 0) {
         disable_interrupts(INT_TBE);
      }
   }
}

void bputc(int c) {
   int restart = 0;

   while (tx_counter > (TX_BUFFER_SIZE - 1)) {
      restart_wdt();
   }

   if (tx_counter == 0) {
      restart = 1;
   }
   tx_buffer[tx_wr_index++] = c;
   if (tx_wr_index > TX_BUFFER_SIZE) {
      tx_wr_index = 0;
   }
   tx_counter++;
   if (restart == 1) {
      enable_interrupts(INT_TBE);
   }
}

void main() {

   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_wdt(WDT_ON);
   setup_timer_0(RTCC_INTERNAL|RTCC_OFF|RTCC_8_bit);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   enable_interrupts(global);
   
   a = 3;

   while (TRUE) {
      restart_wdt();
      printf(bputc,"1. A = %ld\n\r",a);
      b = a * 1440;
      printf(bputc,"2. B = %ld\n\r",b);
      if (--a == -4) {
         a = 3;
      }
      delay_ms(1000);
   }
}


Note that I get the same behaviour if I put a "L" behind the 1440:
Code:
b = a * 1440L;


Here's the list file, if it helps. I don't think this is a printf problem, but rather is some sort of math bug. I'd appreciate some input.

Code:
....................    while (TRUE) {
....................       restart_wdt();
0304:  CLRWDT
....................       printf(bputc,"1. A = %ld\n\r",a);
0306:  CLRF   x70
0308:  MOVF   x70,W
030A:  RCALL  00A0
030C:  INCF   x70,F
030E:  MOVWF  00
0310:  MOVWF  x7A
0312:  RCALL  0126
0314:  MOVLW  07
0316:  SUBWF  x70,W
0318:  BNZ   0308
031A:  MOVLW  10
031C:  MOVWF  FE9
031E:  MOVFF  6D,72
0322:  MOVFF  6C,71
0326:  RCALL  0160
0328:  MOVLW  0A
032A:  MOVWF  x7A
032C:  RCALL  0126
032E:  MOVLW  0D
0330:  MOVWF  x7A
0332:  RCALL  0126
....................       b = a * 1440;
0334:  MOVFF  6D,71
0338:  MOVFF  6C,70
033C:  MOVLW  05
033E:  MOVWF  x73
0340:  MOVLW  A0
0342:  MOVWF  x72
0344:  BRA    024A
0346:  MOVFF  02,6F
034A:  MOVFF  01,6E
....................       printf(bputc,"2. B = %ld\n\r",b);
034E:  CLRF   x70
0350:  MOVF   x70,W
0352:  RCALL  00C8
0354:  INCF   x70,F
0356:  MOVWF  00
0358:  MOVWF  x7A
035A:  RCALL  0126
035C:  MOVLW  07
035E:  SUBWF  x70,W
0360:  BNZ   0350
0362:  MOVLW  10
0364:  MOVWF  FE9
0366:  MOVFF  6F,72
036A:  MOVFF  6E,71
036E:  RCALL  0160
0370:  MOVLW  0A
0372:  MOVWF  x7A
0374:  RCALL  0126
0376:  MOVLW  0D
0378:  MOVWF  x7A
037A:  RCALL  0126
....................       if (--a == -4) {
037C:  MOVF   x6C,W
037E:  BTFSC  FD8.2
0380:  DECF   x6D,F
0382:  DECF   x6C,F
0384:  MOVF   x6C,W
0386:  SUBLW  FC
0388:  BNZ   0394
038A:  INCFSZ x6D,W
038C:  BRA    0394
....................          a = 3;
038E:  CLRF   x6D
0390:  MOVLW  03
0392:  MOVWF  x6C
....................       }
....................       delay_ms(1000);
0394:  MOVLW  04
0396:  MOVWF  x70
0398:  MOVLW  FA
039A:  MOVWF  x71
039C:  BRA    026A
039E:  DECFSZ x70,F
03A0:  BRA    0398
....................    }
03A2:  BRA    0304
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Feb 06, 2007 6:32 pm     Reply with quote

I made a shorter test program and found that the order of
operations is important. I tested this with PCH vs. 3.249.

Here are the results from the program below.
Quote:

B = -1184 // It fails if the variable comes first.

B = -1440 // It's correct if the constant comes first.

It doesn't matter if I put 'L' after all the constants. It doesn't help.

Code:

#include <18F4580.h>
#fuses HS, NOWDT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

signed int16 a, b;

//=======================
void main()
{
// This one fails.
 a = -1;
 b = a * 1440;
 printf("B = %ld \n\r", b);

// Now put the 1440 first.  It works.
 a = -1;
 b = 1440 * a;
 printf("B = %ld \n\r", b);
while(1);
}


This item from the old versions page is suspicious:
Quote:
3.170 A type conversion problem involving signed numbers and constants is fixed.

Maybe the old regression testing problem ?

I'm not sure that they fixed it then, because I installed vs. 3.173 and
it failed. I don't have 3.170. It also fails with vs. 4.023.
Then I went back to 3.148 and it worked:
Quote:

B = -1440

B = -1440
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Tue Feb 06, 2007 6:48 pm     Reply with quote

PCM,

Thanks for the tip. I'll switch the order in my real program. How frustrating to chase this thing all day! Twisted Evil

I'd alert them to this bug but the last time that I did tell them about a bug was about 18 months ago and they never did fix it in the end. Probably no use in alerting them to this.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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