Reading the Compiler documentation I found the fract (_Fract) and accum (_Accum) native types. Looking at the fir() function help, I see the two versions, fir_fr16() and fir_fx16(). To my understanding, (short) fract is identical to fract16, so I was wondering what is the difference between the functions, and can I use them interchangeably?

Is the support for fract16 and _Fract types guarantied in the future?

Hi Yaniv,

Firstly, the fxbits family of functions will compile to no machine instruction so long as (i) optimisation is enabled (ii) the size in bits of the integer operand is the same as the fixed-point result.

So, with optimisation enabled, rbits, lrbits, urbits etc. will not yield a real machine instruction. However kbits and ukbits will, as they have to saturate the larger integer operand down to the size of the accum result.

As for casting integer types, the ANSI C standard has this to say (deep breath):

"When a value with integer type is converted to another integral type, if the value can be represented by the new type, its value is unchanged.

When a signed integer is converted to an unsigned integer with equal or greater size, if the value of the signed integer is nonnegative, its value is unchanged. Otherwise, if the unsigned integer has greater size, the signed integer is first promoted to the signed integer corresponding to the unsigned integer; the value is converted to unsigned by adding to it one greater than the largest number that can be represented in the unsigned type.

When a value with integral type is demoted to an unsigned integer with smaller size, the result is the nonnegative remainder on division by the number one greater than the largest unsigned number that can be represented in the type with smaller size. When a value with integer type is demoted to a signed integer with smaller size, or an unsigned integer is converted to its corresponding signed integer, if the value cannot be represented the result is implementation-defined."

So, paraphrasing: converting to unsigned integer is well-defined by the standard in any case, even if the operand is out-of-range of the destination type. However conversion to signed is done by value, and is implementation-defined (an implementation can do whatever it likes) if the operand is out-of-range of the destination type. The difference between signed and unsigned types was why I used the word "generally" in my first reply - I was glossing over the subtleties.

In terms of truncation and extension, the standard does therefore imply that sign- and zero-extension should be used to convert to a larger-sized integer (because the value does fit). For unsigned, truncation must be used to convert to a smaller size. For signed integers, an implementation doesn't have to use truncation, but it will almost always be the cheapest option, so implementations will usually use it.

Hope that helps,

Michael.