|
|
View previous topic :: View next topic |
Author |
Message |
pilar
Joined: 30 Jan 2008 Posts: 197
|
Error with signed integer operations |
Posted: Wed Jul 07, 2021 6:54 pm |
|
|
Hi, I am use a Pic18F4620 with CCS compiler V4.074, I am doing a simple operation with signed integers of 8bits and 16 bits, the thing is that I have the variable "myRSSIValue8" that I collect from the array valueRSSI[] whose value is -77, but when I use this variable when doing the multiplication operation and add the value that I get it is 50, but when I do the same operation but instead using a constant (-77) the value I get is 18, why? What is my error?
Here is my code:
Code: | #include <18F4620.h>
#fuses HS,WDT32768,PROTECT,NOLVP,NOBROWNOUT
#use delay(clock=20MHz)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)// RS232 Estándar
int8 myCSQValue;
signed int8 myRSSIValue8;
signed int16 myRSSIValue16;
int16 myRSSIValuex;
char Buffer_ValRSSI[5];
char valueRSSI[]={-113,-110,-109,-107,-105,-103,-101,-99,-97,-95,-93,-91,-89,-87,-85,-83,-81,-79,-77,-75,-73,-71,-69,-67,-65,-63,-61,-59,-57,-55,-53};
void main(){
myCSQValue = 18;
myRSSIValue8 = valueRSSI[myCSQValue];
myRSSIValue16 = ((4*(myRSSIValue8)) + 452)*0.125; // Using a variable
printf("myRSSIValue16:%04Ld\r\n",myRSSIValue16);
myRSSIValue16 = ((4*(-77)) + 452)*0.125; // Using a constant
printf("myRSSIValue16:%04Ld\r\n",myRSSIValue16);
while (TRUE);
} |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9240 Location: Greensville,Ontario
|
|
Posted: Wed Jul 07, 2021 7:38 pm |
|
|
my guess...
In CCS C 8 bit 'char' variables are UNsigned, ie 0 to 255 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jul 07, 2021 7:50 pm |
|
|
The values in bold below are both 8 bit, but the result is larger than 8 bits
so it's truncated, and you get the undesired result of -52.
Quote: | myRSSIValue16 = ((4*(myRSSIValue8)) + 452)*0.125;
|
To fix this problem, promote the RSSI variable to be signed 16-bits
as shown in bold below:
Quote: | void main(){
myCSQValue = 18;
myRSSIValue8 = valueRSSI[myCSQValue];
myRSSIValue16 = ((4*((signed int16)myRSSIValue8)) + 452)*0.125; // Using a variable
printf("myRSSIValue16:%04Ld\r\n",myRSSIValue16);
myRSSIValue16 = ((4*(-77)) + 452)*0.125; // Using a constant
printf("myRSSIValue16:%04Ld\r\n",myRSSIValue16);
|
|
|
|
pilar
Joined: 30 Jan 2008 Posts: 197
|
|
Posted: Wed Jul 07, 2021 7:51 pm |
|
|
Quote: | In CCS C 8 bit 'char' variables are UNsigned, ie 0 to 255 |
I have declared the array as a signed integer and I keep getting the same result, I don't understand why?
Code: | signed int8 valueRSSI[]={-113,-110,-109,-107,-105,-103,-101,-99,-97,-95,-93,-91,-89,-87,-85,-83,-81,-79,-77,-75,-73,-71,-69,-67,-65,-63,-61,-59,-57,-55,-53}; |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jul 07, 2021 8:23 pm |
|
|
You missed my post given above. |
|
|
pilar
Joined: 30 Jan 2008 Posts: 197
|
|
Posted: Wed Jul 07, 2021 8:44 pm |
|
|
PCM programmer, I am sorry, I had not seen your answer, yes you are right that was the problem
Thank you! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19535
|
|
Posted: Thu Jul 08, 2021 12:05 am |
|
|
As soon as I saw 'multiply', and signed 8bit, I thought 'overflow'. I see
PCM has spotted the same.
Can I make one alternate suggestion:
Code: |
myRSSIValue16 = ((4L*myRSSIValue8) + 452)/8; // Using a variable
|
Two things to this. The problem comes about because in the multiplication,
anything over 63, will result in a signed int8 overflowing. Now when you
perform arithmetic in C, the original 'rules', were to use the 'highest' type
from the two values. So 4 (int8), times the signed 8bit myRSSIValue8, uses
signed 8bit arithmetic. Overflow. Now PCM has shown how to instead force
myRSSIValue8 to be treated as signed 16bit. Perfect answer. However the
compiler actually codes this a little less efficiently than if you do it the 'other
way round', and have the constant '4' declared as 16bit (4L). Since 'signed'
always has priority over 'unsigned', the result will be to use signed 16bit
arithmetic, and you should find the code is a little quicker, and smaller
doing it this way (only about one byte though!).
Then the second bit is the multiplication by 0.125.
Dividing by eight, instead makes it use int16 arithmetic again, and since
the result so far is already 'signed', this is done using signed int16.
Now, re-coding as I show, reduces this code (on a quick test compile),
from 674 bytes, to 376 bytes. It still gives the right result.
Sizes of elements, and how this affects the arithmetic used, is a thing that
you really have to get your head around in C. Historically in all C's.
However in recent years, C's on things like the PC, have become rather
'forgiving' of this, since they use the hardware FPU, and so an int8 by
int8 multiplication will usually be using something like 80 bit registers
and overflows are automatically handled, and so don't give the problem
seen here!...
The 'saving' seen by the different approach depends on the processor used.
For some reason 'casts' seem to be very inefficient on the DsPIC's now,
which is why I try to avoid them. The speed gain is much bigger on the
PIC's that don't have hardware mul & div. On chips with these instructions
the original approach may well be nearly as fast, but the alternative is
still massively smaller. On chips without these instructions, the alternative
is nearly 50% faster!... |
|
|
|
|
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
|