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 CCS Technical Support

Can the difference between two unsigned int16 be negative?

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



Joined: 29 May 2015
Posts: 7
Location: Lahore

View user's profile Send private message AIM Address

Can the difference between two unsigned int16 be negative?
PostPosted: Mon Jun 15, 2015 2:55 am     Reply with quote

Hello Guys,

Can the following statement result in negative when difference is calculated between two unsigned int16 values?
Code:

unsigned int8 rem;
unsigned int16 first = 10, second = 20;

if((first - second) < 21)
{
        rem = first - second;
}

I expect the 'rem' variable to only have values '0' to '20'. Will this code snippet yield correct values for 'rem' variable?

I am using CCS 5.042, target = 18f452
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Mon Jun 15, 2015 3:46 am     Reply with quote

Yes, the difference between two unsigned int16s (or any other size of int other than int1) can be negative. However, when calculated without casting/promoting one or both to signed, the result will be a very high (> half the unsigned range) positive value.

so consider the following:

Code:

unsigned int16 a = 1;
unsigned int16 b = 2;
unsigned int16 c;
signed int16 d;

c = a - b; // gives c = 65535 - "wrong" but there is no way to represent the correct result.
d = a - b; // arguably incorrectly, but gives -1 (actually 65565 as above, which is over the range of signed int16, but when interpreted as signed int16 is -1. This is becuase the underlying computational arithmetic is the same for both types with two's complement representation.
d = (signed int16) a - b; // gives d = -1;
shehwar



Joined: 29 May 2015
Posts: 7
Location: Lahore

View user's profile Send private message AIM Address

Thank you RF_Developer
PostPosted: Mon Jun 15, 2015 4:01 am     Reply with quote

Thanks for your reply, that quite satisfying. Now a simple question remains from the code snippet. If i want to have 'rem' variable to have values from '0' -- '20', would the following if condition suffice:
Code:

if((first - second) < 21 && (first - second) > 0)
{
rem = first - second;
}

given:
Code:

unsigned int8 rem;
unsigned int16 first = 10, second = 20;
kWoody_uk



Joined: 29 Jan 2015
Posts: 47
Location: United Kingdom

View user's profile Send private message

PostPosted: Tue Jun 16, 2015 7:43 am     Reply with quote

I think that :-

Code:

if ( ( first - second ) < 21 ) {
    rem = first - second;
}


Will perform the same for you as this will be testing for values between 0 and 20.


Keith
rikotech8



Joined: 10 Dec 2011
Posts: 376
Location: Sofiq,Bulgariq

View user's profile Send private message

PostPosted: Tue Jun 16, 2015 12:22 pm     Reply with quote

Code:
rem = first - second;

rem will never be negative since it is unsigned value. Even if you explicitly cast the result to be signed int like this:
Code:
rem = (signed int)(first - second)
rem will be positive. Otherwise it is non sense to declare a variable as unsigned if it is able to accept negative values.
_________________
A person who never made a mistake never tried anything new.
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Tue Jun 16, 2015 11:27 pm     Reply with quote

is this 8th grade algebra ????????
or the twilight zone ?
FYI:Let me ask the poster ,
CAN the difference between two negatives can be a POSITIVE ??...
Shocked Confused Very Happy Cool Laughing Laughing Laughing Laughing Laughing Laughing
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Wed Jun 17, 2015 3:06 am     Reply with quote

asmboy wrote:
is this 8th grade algebra ????????

...

CAN the difference between two negatives can be a POSITIVE ??


In mathematics, including algebra, yes, of course the the difference of two negatives can be positive, just as the difference between two positives can be negative. The difference between any two numbers can be positive, negative or zero.

This is NOT mathematics however. It's computation. Stuff works somewhat differently.

With subtraction of signed ints there's no problem. All the possible results (provided they don't overflow) can be represented.

The problems come when when we're dealing with unsigned ints. Unsigned numbers must always be positive or zero. The problem is that we can't represent a negative result as an unsigned number. So what happens?

For the purposes of this discussion, I'm assuming we're woking with two's complement computational arithmetic, as has been standard for practically all processors of the last forty years (but not all ADCs incidenntally - there are some sign and magnitude bipolar ADCs out there still) All PICs use two's compliment. If we try to interpret what should be a negative number as an unsigned int then it will appear to be a very high (half or above of the possible representable states) positive number, i.e. it has the top bit set. For example for unsigned int16, -1 would appear, if interpreted as unsigned as 65535, and -32768 as 32768.

In C, the type of the result of an expression is the "highest" type to which all the operands are promoted. This means if the operands are all unsigned, the result is unsigned. It doesn't matter what its assigned to, or used as, nor, most importantly, what the programmer would like it to be, or assumes it to be. It doesn't matter that a subtraction with unsigned ints is assigned to a signed int, the expression is calculated using unsigned integer computatonal arithmethic, and that result converted (cast in C terms) to signed.

With smallish (i.e. less than half the range representatble by the types) what happens? As soon as you get above half the range there is potential for overflow which complicates things.

What is the type of (unsigned int16 a - unsigned int16 b)? Unsigned int16. If b is greater than a, its technically an overflow giving a mathematically wrong, but computationally expected very high positive number.
What is the type of (signed int16 a - signed int16 b )? Signed int16. Result will be correct.
What is the type of (signed int16 a - unsigned int16 b)? Signed int16, with the unsigned being promoted (automatically converted) to signed int16 before the subtraction was made.

It doesn't matter is an expression is assigned to a different type, or compared to a different type. In C, the expression is always computed using the types in the expression itself, and only itself. Be aware that other languages may work differently.

Executive summary:

There are better (meaning less prone to confusion) ways of checking a number lies within a range than using subtraction. Its best to explictily compare against the bounds. For example:

Code:

if (a >= 20 && a < 40)
{
...
}


is a lot clearer and less liable to computational confusion than:

Code:

if ((a  - 20) < 20)
{
...
}

Here there is no explict check of the lower limit and it relies on an assumption of the expression being done in a certain way that's not necessarily what actually happens...
shahrokh_m



Joined: 30 Jun 2014
Posts: 8

View user's profile Send private message

PostPosted: Fri Feb 03, 2017 10:40 pm     Reply with quote

Hi friends.
I have same question.
In this code, last else if condition is never run. Why?
Code:

signed int16 delta;

delta = sensor[1] - sensor[2];

if(20 < delta) {
  move_left();
  lcd_gotoxy(1,2);
  lcd_putc("   MOVE    M1            ");
  delay_ms(100);
  }
else if(-20 < delta < 20) {
  move_direct();
  lcd_gotoxy(1,2);
  lcd_putc("   MOVE    M2            ");
  delay_ms(100);
  }
else if(delta < -20) {
  move_right();
  lcd_gotoxy(1,2);
  lcd_putc("   MOVE    M3            ");
  delay_ms(100);
  }

delta var can be negative or positive. Could you help me why last else if is never run?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Feb 03, 2017 11:42 pm     Reply with quote

Quote:
else if(-20 < delta < 20) {

See the answers section of this post:
http://stackoverflow.com/questions/6961643/usage-of-greater-than-less-than-operators
shahrokh_m



Joined: 30 Jun 2014
Posts: 8

View user's profile Send private message

PostPosted: Sat Feb 04, 2017 12:13 am     Reply with quote

Thanks a lot.
according the link, second "else if" executed, so the last "else if" does not work.


Last edited by shahrokh_m on Sat Feb 04, 2017 12:34 am; edited 1 time in total
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Feb 04, 2017 12:31 am     Reply with quote

Make a test program. Run it in MPLAB vs. 8.92 simulator. Get rid of your
sensor math and replace it with 'delta' set to -40. According to your
thinking, it should execute "case 3", as shown below. But it actually
executes "case 2". It never gets to case 3. Here is the result of running
the program shown below in MPLAB simulator:
Quote:

case 2
Done

Read the stackoverflow.com link again to see why. It says:
stackoverflow wrote:
The < operator associates left-to-right, just like the + operator. So just as
a + b + c really means (a + b) + c, a < b < c really means (a < b) < c.
The < operator yields an int value of 0 if the condition is false, 1 if it's
true. So you're either testing whether 0 is less than c, or whether 1 is
less than c.

And 0 or 1 are both less than 20, so case 2 will execute. It never gets
to case 3. The link shows how to use parentheses and the && operator to fix it.

Test program:
Code:
#include <18F46K22.h>
#fuses INTRC_IO,NOWDT,PUT,BROWNOUT
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)

//======================================

void main(void)
{

signed int16 delta;

//delta = sensor[1] - sensor[2];

delta = -40;

if(20 < delta)
  {
   printf("case 1 \r");
  }
else if(-20 < delta < 20)
  {
   printf("case 2 \r");
  }
else if(delta < -20)
  {
   printf("case 3\r");

  }

printf("Done \r\r");
 
while(TRUE); 
}
shahrokh_m



Joined: 30 Jun 2014
Posts: 8

View user's profile Send private message

PostPosted: Sat Feb 04, 2017 1:02 am     Reply with quote

The problem was solved with your help.
Infinitely grateful for your kindness. Smile
Ttelmah



Joined: 11 Mar 2010
Posts: 19520

View user's profile Send private message

PostPosted: Sat Feb 04, 2017 6:20 am     Reply with quote

It's worth perhaps just pointing out, that:
Code:

unsigned int8 rem;
unsigned int16 first = 10, second = 20;

if((first - second) < 21)
{
        rem = first - second;
}


Will actually work as posted.

If first is less than second, you will get replies from 65535 downwards as the values get closer. Since all of these will be seen as greater than 20, the test will work as originally posted....
Where it would go wrong, would be if you had an 'else', to give a fixed reply for values >20:
Code:

unsigned int8 rem;
unsigned int16 first = 10, second = 20;

if((first - second) < 21)
{
        rem = first - second;
}
else
   rem=20;

Would give an incorrect result, since the -ve results would be seen as greater than 20...

However:
Code:

unsigned int8 rem;
unsigned int16 first = 10, second = 20;

if (first>second)
{
    //+ve results
    if((first - second) < 21)
    {
        rem = first - second;
    }
    else
        rem=20;
}
else
    rem=0;


Would give you '0' for all -ve results, 20, for all values above 20, and 0 to 20 for the values between.
temtronic



Joined: 01 Jul 2010
Posts: 9229
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Feb 04, 2017 6:37 am     Reply with quote

just a comment...

I really hate seeing 'rem' as a variable name.
Everytime I saw it, I thought 'remark'....stuff after it doesn't matter..

I'd prefer to see 'remainder' or 'result' or 'left_over' or something'.

When I started computers, variables could only be 2 characters long, great for non typists like me! Today's languages allow for 'self-descriptive' variables like 'result_of_A_minus_B'. Makes it easy to 'see' what they are...

Guess I'm getting old and set in my ways.

Jay
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