![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Jerry I
Joined: 14 Sep 2003 Posts: 96 Location: Toronto, Ontario, Canada
|
Error found in shift/multiply code results |
Posted: Mon Feb 02, 2015 8:31 pm |
|
|
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 |
|
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Mon Feb 02, 2015 9:06 pm |
|
|
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);
|
? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
Posted: Tue Feb 03, 2015 1:57 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
newguy
Joined: 24 Jun 2004 Posts: 1903
|
|
Posted: Tue Feb 03, 2015 8:58 am |
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
Jerry I
Joined: 14 Sep 2003 Posts: 96 Location: Toronto, Ontario, Canada
|
|
Posted: Tue Feb 03, 2015 11:14 am |
|
|
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 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
Posted: Tue Feb 03, 2015 12:46 pm |
|
|
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!.... |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|