2008-08-04
Patch Level Update: PICC-18 STD
2008-07-29
Patch Level Update: HI-TECH C PRO for the PIC10/12/16 MCU Family
2008-07-21
NEW - PRO Compiler supporting Microchip PIC32 microcontrollers
Patch Level Update: PICC-18 STD
Patch Level Update: HI-TECH C PRO for the PIC10/12/16 MCU Family
NEW - PRO Compiler supporting Microchip PIC32 microcontrollers
Omniscient Code Generation: as featured in EDN Hot 100 Products of 2007.
|
To represent integer values on a digital computer is relatively easy - you can just interpret a sequence of ones and zeros as the desired value in binary notation, so for example "00101101" is usually understood to mean 45 decimal - but when you want to deal with fractional values, things get a little more involved. One simple way is to use an integer value, but interpret it as a scaled representation of the real value, for example using a scaling factor of 100, so a stored value of 100 means a true value of 1.0, and 50 means 0.5. This is a fixed-point system, and provided the range meets your needs is very easy to use and extremely space-efficient. You can use any integer type as your base type, depending on the range you need, and any scale factor you choose. With our present compilers you will see the following:
Using a scale factor which is a power of your preferred base will greatly simplify your I/O code. Using a scale factor which is a power of 2 will (on a binary computer) maximize your data storage efficiency at the cost of more complex I/O code. The great thing about using an integer-based fixed-point system is that all arithmetic operations are no more expensive, computationally, that the underlying integer operations - to add 1.2 to 0.75 (in the first example above) and print it out requires something like: #include <stdio.h>
typedef unsigned char fixed;
char buffer[5]; /* room for "2.55\0" */
fixed a = 120; /* 1.20 */
fixed b = 75; /* 0.75 */
/* don't use 075 here, or octal will bite you */
fixed c = a + b;
if (c < a || c < b) {
printf("overflow in addition\n");
}
else if (sprintf(buffer+1, "%03u", (unsigned)c) > 2) {
/* move the units digit */
buffer[0] = buffer[1];
/* insert the decimal point */
buffer[1] = '.';
printf("%s\n", buffer);
}
else {
printf("sprintf() failed\n");
}
If a fixed-point system does not meet your needs then you may want to move to a floating-point system, which provides a second, variable and usually exponential, scale factor allowing the range to be greatly expanded when necessary, at the expense of precision. The floating-point system in most common use is defined in IEEE standard 754, and our compilers provide easy access to a simplified implementation of this with the float and double types. Our float uses the following:1 bit of sign information (==1 for negative) The mantissa is a binary fixed-point value, and to get the true value it is multiplied by 2 raised to the power of the exponent. Observant readers will notice that the total number of bits adds up to 25, which is doesn't fit neatly in a group of 8-bit bytes. The most significant bit of the mantissa is always 1 (and any calculation that ends up otherwise is then "normalized" by adjusting the exponent to ensure this remains true) so need not actually be stored. The exponent is stored "excess 127", so a true exponent of 5 would be represented by a stored exponent of 132. A true value of 0.0 is represented by a stored exponent of 0 (with the sign and mantissa parts ignored). Our double is either the same as float, or (selectable at compile time) it uses an extra 8 bits of mantissa for extra precision - the range remains the same.
|
Copyright © 2008 HI-TECH Software • Trademarks • Forum
Site Map