Как автоматически масштабировать значение с плавающей запятой в C?
Автоматическое масштабирование до степеней 1000 имеет тонкие соображения относительно переходов, которые даже закодировали его OP, вероятно, он потерпел бы неудачув угловых случаях.
Давайте попробуем немного другую, но более простую цель: напечатать до 3 значащих цифр со степенью 1000.0
// example output
1.00
9.99
10.0
99.9
100.
999.
1.00k
9.99k
10.0k
...
Код может попытаться сделать это ссвою собственную математику с использованием log()
и т. д., но она всегда будет терпеть неудачу в случаях около 9,995, 99,95, 999,5.
Пусть sprintf()
выполнит тяжелую работу, а затем будет использовать манипуляции со строками.
Первым шагом является печать в строку с использованием "%e"
// sgn dig . digs e sgn expo \0
#define FLT_E2 (1 + 1 + 1 + 2 + 1 + 1 + 5 + 1)
// let us double buffer size as there is little reason to be stingy here.
char buf[FLT_E2 * 2];
// v--- 2 digits after the lead digit
snprintf(buf, sizeof buf, "%.2e", some_float);
Следующим шагом является обработка строки в 3 части и использование "%n"
, чтобы отметить смещение десятичной точкии 'e'
.
int whole, frac, expo, dp, e;
if (sscanf(buf, "%d%n.%d%ne%d", &whole, &dp, &frac, &e, &expo) != 3) {
// value is some non-finite like infinity or not-a-number.
printf("%e", some_float);
return;
}
Теперь переместите expo
на кратное 3 и сдвиньте десятичную точку.
while (expo%3) {
expo--;
buf[dp] = buf[dp+1];
buf[++dp] = '.';
}
Преобразуйте 'e'
в различные Префикс SI .
// TBD code to handle expo out of range [-24 24], left for OP.
char prefix = "yzafpnum kMGTPEZY"[(expo - -24)/3];
if (prefix != ' ') buf[e++] = prefix;
buf[e] = '\0';
Теперь выведите
printf("%s", buf);
Хотя здесь есть много деталей с этими непроверенными фрагментами кода, окончательный код оставлен для формирования OP.
Дополнительные проблемы включают в себя:
обработка специфических для локали десятичных точек, таких как ','
показатели снаружи [-24 ... 24].
μ против вас.