|
|
В printf() от IAR C, например, сначала происходит разложение числа на мантиссу и порядок, далее поразрядное преобразование числа в ASCII текст, а затем округление результата в зависимости от требуемого кол-ва отображаемых десятичных точек дробной части. Причем, последнее сделано несколькоо тупо (корректируется прямо в буфере уже сконвертированная текстовая строка). Некогда я переписал этот алгоритм таким образом, чтобы исходное число разбивалось на целую и дробную части (с заданной точностью) в виде двух целых чисел. После этого их можно несложно вывести в буфер или на ЖКИ.
// Entry: double num - input number in floating-point format
// unsigned char dec_point - number of digits in fractional part
// Uses: lcd_put_char(unsigned char) - outputs a single character
// lcd_put_integer(unsigned int) - outputs a integer
void lcd_put_double(double num, unsigned char dec_point) {
unsigned char ctemp;
signed char iexp10,max_dec_point;
unsigned long uint,ufrac;
if (dec_point>4) dec_point=4;
// *** out a sign
if (num<0) {
lcd_put_char('-');
num=fabs(num);
}
// *** preprocess number: I don't use modf() to split double to
// *** integer and fractional because of a sacrifice of accuracy
// *** in a fractional part. (E.g. modf(16454.8230, &n)=0.8223
// *** instead of 0.8230. So, the difference between result and
// *** reality may be 0.0007 and greater).
// convert number to mantissa and exponent if number >= 10
max_dec_point=dec_point;
iexp10=0;
if (num>=1) {
iexp10=-1;
while (num>=1e11) { // to speed up things a bit
num/=1e10;
iexp10-=10;
}
while (num>=10) {
num/=10;
iexp10--;
}
} else max_dec_point++;
// extract integer and fractional parts
ufrac=0;
while (iexp10<=max_dec_point) {
if (iexp10) {
num-=ctemp=num; // ctemp=digit, num=remainder
num*=10; // prepare for the next shot
ufrac=ufrac*10+ctemp; // accumulate as integer
} else {
uint=ufrac; // remember as uint
ufrac=0;
}
iexp10++;
}
// check if rounding is required (code is unwrapped to speed up a little bit)
if (num>=5) ufrac++;
switch (dec_point) {
case 0: if (ufrac>=1) {uint++; ufrac=0;} break;
case 1: if (ufrac>=10) {uint++; ufrac=0;} break;
case 2: if (ufrac>=100) {uint++; ufrac=0;} break;
case 3: if (ufrac>=1000) {uint++; ufrac=0;} break;
default: if (ufrac>=10000) {uint++; ufrac=0;} break;
}
// output integer part
lcd_put_integer((unsigned int) uint);
// output fractional part
lcd_put_char('.');
lcd_put_fractional((unsigned int) ufrac);
return;
}
E-mail: info@telesys.ru