Ответ: Да, действительно...
(«Телесистемы»: «Конференция «Микроконтроллеры и их применение»»)

миниатюрный аудио-видеорекордер mAVR

Отправлено demask 23 апреля 2003 г. 16:57
В ответ на: Ответ: в сырце слишком накручено много - тяжело разбирать, там все завязано одно на другом... отправлено SOIC 23 апреля 2003 г. 11:52

В 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