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

Error found in shift/multiply code results

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



Joined: 14 Sep 2003
Posts: 96
Location: Toronto, Ontario, Canada

View user's profile Send private message

Error found in shift/multiply code results
PostPosted: Mon Feb 02, 2015 8:31 pm     Reply with quote

I am using Version 5.040 of the compiler.

I ported some code I was using with PIC18 chip, which worked with old compiler V4.14 which worked fine.

I have not checked if this is an error on PIC18 with new V5.040.

I am wanting to use this code with PIC16F1509

I have written small program to display error.

signed int16 inputval = -1;

signed int32 shiftval, multval;

OK multval += (signed int32)(inputval * 256);

ERROR shiftval += (signed int32)(inputval << 8);

I have printed a sample of the error below the code.

Is multiplying variable by 256 --> the same as variable << 8

Let me know if this an error, or am I doing something wrong.

If its an error I will send to support.

Thanks.

Jerry

Code:


#device PIC16F1509

//#IFDEF PIC_16F1509
  #include <16F1509.h>
//   #include "defs_1829.h"
  #fuses intrc_io, nowdt, noprotect, nolvp, put
  #fuses nomclr, nodebug

  #device *=16
  #device adc=8
//#ENDIF

#define CLOCK16MHZ

#case

#ifdef CLOCK16MHZ
  #use delay(clock=16000000, internal)    //one instruction=0.2us
#endif

#define BAUD1_SPEED 9600
#define BAUD2_SPEED 19200

#use rs232(baud=BAUD2_SPEED,xmit=PIN_B7,rcv=PIN_B5, ERRORS)


signed int16
inputval;                           


signed int32
multval, shiftval;               


void main()
{
    setup_adc(ADC_OFF);

    inputval = 0;
    multval = 0;
    shiftval = 0;

    printf("Shift Error Test \r\n");

    inputval = -1;

    while(TRUE)
    {
        multval += (signed int32)(inputval * 256);
       
        shiftval += (signed int32)(inputval << 8);

   
        printf("MultVal = %ld  Div256 = %ld  ShiftVal = %ld Div256 = %ld\r\n", multval, multval / 256, shiftval, shiftval / 256);
        delay_ms(2000);

    }
}

Output

MultVal = -256 Div256 = -1  ShiftVal = 65280 Div256 = 256
MultVal = -512 Div256 = -2  ShiftVal = 130560 Div256 = 510
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Mon Feb 02, 2015 9:06 pm     Reply with quote

The shift left << works no matter if the number is signed or not.

For example:
4 << 2 (same thing as 4 * 4):
0b00000100 << 2 = 0b00010000 = 16d

-4 << 2 (same thing as -4 * 4):
0b11111100 << 2 = 0b11110000 = 240d. For an int8, this is also -16 if the compiler treats the int8 as signed.

Could be a change in how the compiler is treating the result or an intermediate. Have you tried

Code:
shiftval += ((signed int32)inputval << 8);


?
Ttelmah



Joined: 11 Mar 2010
Posts: 19378

View user's profile Send private message

PostPosted: Tue Feb 03, 2015 1:57 am     Reply with quote

No, shift is not the guaranteed to be the same as multiply for a signed.

Quote from K&R (in the description appendix):
"The value of E1<<E2 is E1 (interpreted as a bit pattern) left-shifted E2 bits, in the absence of overflow, this is equivalent to multiplication by 2^E2, The value of E1>>E2 is E1 right shifted E2 bit positions. The right shift is equivalent to division by 2^E2 if E1 is unsigned or it has a non-negative value, otherwise the result is implementation defined".

There are about three critical parts in this:
1) In the absence of overflow.
-ve numbers have '1' in the top bit. So will always overflow on a left shift.
2) 'if E1 is unsigned or it has a non-negative value'.
So the result is _not_ defined for a -ve value.
3) 'result is implementation defined'.
No guarantees what will happen.....

For this reason the general C advice is to _only_ treat rotation as equivalent to multiplication/division for unsigned values.

For left shifting, -16, is stored as 1111111111111000. Rotate this left four times, and you get 1111111100001111, which codes as -241. This is because it is always overflowing at the top.

Switching to int32, solves this because it generates:
00000000000000001111111111110000
shifting gives:
(1111)1111111100000000 which then drops the high bits to give 1111111100000000 which is -256. By using the larger type, you are avoiding the overflow.

There is actually no point in using rotations for this in CCS. The compiler is smart, and if you say val*4, for an unsigned value, it will automatically substitute <<2.

The new compiler is actually doing it right. It was the old compiler that was faulty, they were dropping the overflowed bit, so allowing it to work. CCS have fixed this. Your 'expectations' were wrong.
newguy



Joined: 24 Jun 2004
Posts: 1903

View user's profile Send private message

PostPosted: Tue Feb 03, 2015 8:58 am     Reply with quote

Ah. Easiest way around this then is to cast the signed int he wants to multiply (shift) to an unsigned int. Result will be what is expected. Or should be.
Jerry I



Joined: 14 Sep 2003
Posts: 96
Location: Toronto, Ontario, Canada

View user's profile Send private message

PostPosted: Tue Feb 03, 2015 11:14 am     Reply with quote

Thanks Ttelmah

Great explanation of the problem.

It looks like the error is also in the Microchips C18 compiler because the code I used was ported from an AN696.

Thanks
Ttelmah



Joined: 11 Mar 2010
Posts: 19378

View user's profile Send private message

PostPosted: Tue Feb 03, 2015 12:46 pm     Reply with quote

As I pointed out, it is not an error.....

You need to understand the way -ve numbers are coded, and realise that rotation is not designed to give multiplication on these.
The same would apply to unsigned numbers when they get up to the top of the range. Try rotating +32768 left by one in an unsigned int16. You won't get 65536, but 1!....
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