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

Type conversion problem

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



Joined: 23 Aug 2006
Posts: 19

View user's profile Send private message Send e-mail

Type conversion problem
PostPosted: Sun Feb 04, 2007 4:23 pm     Reply with quote

Hi again,

This time I have a problem with the automatic type conversion that should work in C. I tried the following short program fragment (excluded init of RS232 etc) :

signed int16 testValue;
float x;
float corr;

testValue = 50;
corr = 1.1;
x = testValue * corr;
printf("result (no cast) %f\n\r", x);

testValue = 50;
corr = 1.1;
x = (float)(testValue) * corr; // note the cast to float
printf("result with cast %f\n\r", x);

and the result is as follows:

result (no cast) 0.00.
result with cast 55.00.

It seems that the compiler does not convert the signed int16 to a float before the assignment to x. Or maybe worse, it does not convert testValue to a float before the multiplication with corr, which is of type float.

Anyone seen anything like this ? My compiler version is 4.023 but it does not work with version 3.245 either. I am not very fluent in PIC assembler so I need help with this, perhaps someone could try this and look at the list file. The PIC I am using is a PIC18LF258.

Best Regards
Thomas Johansson
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Feb 04, 2007 5:24 pm     Reply with quote

This is a common topic on the forum:
http://www.ccsinfo.com/forum/viewtopic.php?t=26384&highlight=automatic+type+promotions
http://www.ccsinfo.com/forum/viewtopic.php?t=19693&highlight=type+promotions
http://www.ccsinfo.com/forum/viewtopic.php?t=18505&highlight=promote

Read Ttelmah's post at the end of this thread for an explanation
of why CCS does this:
http://www.ccsinfo.com/forum/viewtopic.php?t=21014&highlight=promote
thomasj50



Joined: 23 Aug 2006
Posts: 19

View user's profile Send private message Send e-mail

PostPosted: Sun Feb 04, 2007 5:53 pm     Reply with quote

Ok, i didn't see those topics. Regarding Ttelmah's post at the end: My problem is not of the type small type * small type => bigger type, but a multiplication of an int16 with a float, and the compiler does not promote the int before the multiplication, which, whichever way you look at it, must be regarded as a bug. I can't see how it would be useful in any context, microcontroller or otherwise.

I quote the printed manual (July 2003) on page 227, where the question is "How are type conversions handled ?"

" The compiler provides automatic type conversions when an assignment is performed. Some information may be lost if the destination can not properly represent the source."

The rest of the answer is about multiplying small types and not getting them promoted to the result type, which I would not expect of any C compiler.

None of the topics mentions the problem with int16 * float. I will report this to the ccs support and see what they say (but they never answer any bug reports anyway :-)

Best Regards
Thomas Johansson
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Feb 04, 2007 6:13 pm     Reply with quote

Here's one on casting to a float. See my post at the end:
http://www.ccsinfo.com/forum/viewtopic.php?t=28801&highlight=cast+float
thomasj50



Joined: 23 Aug 2006
Posts: 19

View user's profile Send private message Send e-mail

PostPosted: Sun Feb 04, 2007 7:22 pm     Reply with quote

Hi,

Ok, thanks for all the help. I guess I have to live with this quirk, but I must say that it is becoming a bit tricky to remember all the little exceptions :-) In the last two monts or so I have found four different 'behaviours' that mostly have been recognized as bugs by ths forum - I think they are but I might have a quite non-flexible attitude towards issues of standards compliance and what is said about a function in the manual and the actual behaviour.

Best Regards,
Thomas Johansson
Ttelmah
Guest







PostPosted: Mon Feb 05, 2007 10:41 am     Reply with quote

Read the quote aready given. It _does_ apply.
Generally in C, if you (for instance), multiply two variables of different tyes, the compiler will use the 'higher' type for the arithmetic. CCS, quite deliberately does not do this. It applies with integers, float, etc. etc.. It is done to save ROM space, but requires _you_ to make a conscious decision to use the larger arithmetic if required...

Best Wishes
thomasj50



Joined: 23 Aug 2006
Posts: 19

View user's profile Send private message Send e-mail

PostPosted: Tue Feb 06, 2007 10:16 am     Reply with quote

But your post of Nov 18, 2004 only talks about multiplying 8 bit integers and then expecting 16 bits as a result, i.e. promoting one or both of the operands to the same type as the _result_ - this works in for instance VC++, which surprises me, since I would never trust a compiler to do this kind of promotion for me.

I talk about promoting _all_ operands in an expression to float if _any_ of the operands are floats, since there is a difference between multiplying integers (one function in the library) and multiplying floats (another function). You can never get any useful result from multiplying a float with an integer unless you first convert the integer to a float, and since CCS does not do this, I call it a bug. Which function should the compiler use ? Neither one will work.

Best Regards,
Thomas Johansson
Ttelmah
Guest







PostPosted: Tue Feb 06, 2007 11:43 am     Reply with quote

In C (in common with most other languages), an expression is 'broken down' before evaluation. So (for instance), the operations:

a*b

and

(a*b)*c

are treated as (a*b) in the first case, and as (a*b), and then the result *c in the second. Hence the behaviour for a 'long' expression, is identical to that for a single sub 'part'. This includes dealing with a 'result', since the result for each sub component, is what is fed into the next bit. In C in general, the entire operation is propagated 'up'. The actual rules in C, are that if either component in an arithmetic operation is of a higher type, then conversion 'up' will occur on the lesser value before the operation. The types are considered to order:
double
float
long
int

(there is actually a relatively complex set of rules dealing with signed/unsigned as well).
'=', is considered to be an arithmetic operator, just like *. Hence the same propagation rules should apply. However it has the lowest order of precedence, baring ','.
So a multiplication of a long int, and a float, will always result in the values being converted to 'float' before the arithmetic (even if this resuts in precision loss), in normal C.
Now the particular post I made, is to do with the logic of conversions. An 8*8 multiplication, _requires_ a 16bit result. It cannot actually be performed in an 8bit value. Hence, since the types become automatically propagated up to the higher type by the nature of the arithmetic, the '=', should inherit this longer result, if the storage offered will take it. However in CCS, this does not occur. This is exactly the same 'jump' needed when dealing with a string of operations (in fact no 'C', _should_ convert all the values in a formula to 'float', just because one is 'float', the conversion should only happen, when the first 'float' value is met, using the rules of precedence along the formula. All the arithmetic 'up to' this point, can happily be performed in the lower type, without affecting the result at all....). CCS, elect not to automatically convert in 90% of cases. Now in terms of 'logic', this is annoying, but it does make good sense, when dealing with a chip with very limited space, forcing the programmer, to consciously 'think' about the arithmetic involved. Their rules are much simpler than normal, taking the _first_ value only in an operation for the arithmetic (and the second, for '=').
Now, I agree it is totally wrong, that this is not properly documented. However for the smaller chips, for an embedded language, it would also be wrong, to leap into using the normal C rules, since in most cases, these would result in code that just wouldn't fit in the chip!.
You can make the 'float' arithmetic type be used, by simply putting the 'float' value first, or using a cast. On the latter compilers (if you don't have warnings supressed), you will receive a warning about the possible loss of precision, when this problem appears.

Best Wishes
thomasj50



Joined: 23 Aug 2006
Posts: 19

View user's profile Send private message Send e-mail

PostPosted: Wed Feb 07, 2007 5:29 pm     Reply with quote

Hi again,

Ok i see your point, but I'd still rather have a compiler that generated a too big a program rather than a 'faulty' one. One thing: I don't see what you mean by first saying

"The actual rules in C, are that if either component in an arithmetic operation is of a higher type, then conversion 'up' will occur on the lesser value before the operation."

and then

"in fact no 'C', _should_ convert all the values in a formula to 'float', just because one is 'float', the conversion should only happen, when the first 'float' value is met, using the rules of precedence along the formula. All the arithmetic 'up to' this point, can happily be performed in the lower type, without affecting the result at all....). "

Actually VC++ gives the same result (correct) for

byte * byte * float
and
float * byte * byte,

but if I interpret your answer correct the first one should not convert the result from byte * byte to float until the parser got to the 'float', in which case it would be 'too late'.

But I might have misunderstood you or the rules. Well anyway, thanks for your input, it made me find a few more ticking timebombs in the program ...

Best Regards,
Thomas Johansson
Ttelmah
Guest







PostPosted: Thu Feb 08, 2007 6:12 am     Reply with quote

The point I was making, was that the conversion should not be on an 'all' basis'. Imagine this:

float = float * (int * int)

What should happen following the C rules, is that because 'int * int evaluates first (the brackets force this), and both parts are integer, this should be performed in integer arithmetic. Then the result of this, should be converted to float, and the float multiplication performed (since there is a 'float' involved in the sum). Now this can be very important, since if the components in the 'int' part, are perhaps 32bit values, you can get greater precision working in integers, than in floats...

Now in your example, a normal C, will in fact evaluate the 'byte * byte', using integer arithmetic. However it will also _correctly_ know that to multiply a byte times a byte, can generate a 16bit result, and handle this (if you look for example, at the 8*8 hardware multiplier built into the PIC chips, this generates a 16bit result). Where CCS goes really screwy, is in discarding the overflow, before then looking at the next part (which was exactly what my original post complained about...).
In fact as posted, something 'worse' is happening in your example, and this I have not seen. If the problem was just with type casting, the first result, should be _50_, not '0'. Performing '1.1' time '50', in integer arithmetic, should give 50...
One thing that might be causing a problem, is the '%f' fault. Using '%f', without a width specifier in CCS, gives 'screwy' outputs a lot of the time. You might want to try with a width specifier (%6.3f for example), and see if your result changes. You may be suprised!...

Best Wishes
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