我正在为电子应用输出电容值,我想以行业标准的方式格式化值,即2 s.f.使用SI标量前缀替换小数点,例如4.7µF
变为4u7
,220nF
变为220n
。优雅似乎正在逃避我,我能想到的最好的事情是这个笨拙的混乱:
float cap = 4.7 * 10^(-6); // 4.7µF
...
// work out the multiplication factor and appropriate SI scalar symbol
// here we hardcode it
float mul = 10^(-6);
char symbol = 'u';
...
// split cap/mul to integer and integral parts
float pre, post;
pre = modf( cap/mul, &post );
// simple case, we have no integral part at 2 s.f.
// (accounting for rounding errors)
if ( pre >= 10.0f || post < 0.05f )
{
printf("%d%c\n", pre, symbol )
}
else
{
// convert post to a single digit integer by
// rounding to 1sf and multiplying by 10
post *= 10.0f;
post = floor( post+0.5f );
// print
printf( "%.0f%c%.0f\n", pre, symbol, post );
}
其他人可以做得更好吗?
答案 0 :(得分:0)
使用sprintf("+4.1e")
进行主转换,然后对字符串进行后处理。
#include <stdio.h>
// Convert value to text showing 2 significant digits and metric prefix for decimal point
int EEPrint(char dest[6], double x, char Unit) {
char buffer[1 + 1 + 1 + 1 + 1 + 1 + 4 + 1 + 8 /* spare */]; // note 1
snprintf(buffer, sizeof(buffer), "%+4.1e", x); // note 2
int I, F, Expo;
char Extra;
if ((sscanf(buffer, "%2d%*[^0-9]%1de%d%c", &I, &F, &Expo, &Extra) != 3)
|| (Expo < -24) || (Expo > +26) || (!dest)) { // note 3
return 1; // fail
}
Expo -= -24; // a yocto is power(10,-24)
static char Prefix[] = "yzafpnum.kMGTPEZY"; // Greek mu is '\u03bc'
Prefix[8] = Unit; // Replace no-prefix with unit
char DP = Prefix[Expo / 3];
// note 4
switch (Expo % 3) {
case 0: snprintf(dest, 6, F ? "%d%c%d" : "%d%c", I, DP, F); break; // Note 5
case 1: snprintf(dest, 6, "%d%d%c", I, F, DP); break;
case 2: snprintf(dest, 6, "%d%d0%c", I, F, DP); break;
}
return 0;
}
/* General
* When the SI prefix is power(10,0) the typical symbol used in electronic notation
* is 'R' for resistors, 'L' for inductors, etc.
* The longest `dest` string occurs with results like "-120k".
* The shortest `dest` string occurs with results like "0R".
* note 1
* buffer size [1 sign][1 digit][1+ dp][1 digit]e[1 sign][4 digit][1 NUL][8 spare]
* note 2
* Use sprintf() to do the heavy lifting to get the **best** double to text conversion.
* All rounding, +/-0, Nan , Inf, sub-normal issues are well defined.
* The rest of the code deals with textual shifting and exponent replacement.
* note 3
* Nan , Inf detected and rejected.
* very small (<= 9.949990e-25) and very large (>= 9.950010e+26) rejected.
* NULL dest rejected.
* negative numbers accepted.
* -0 loses its sign. To retain, make I a double and change formats
* NOT dependent on decimal point being a '.'.
* 'Extra' detects unexpected extra text and rejects conversion.
* note 4
* At this point there are _many_ ways to proceed.
* I went for the method that is easy to alter and maintain.
* note 5
* OP's appears to want values like 1,000 --> "1k" rather than "1k0".
* I coded per OP, but recommend showing 2 significant digits in this case.
*/
#include <float.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
static int EEprint_Test(int Expect, double x, char Unit) {
char buffer[6];
strcpy(buffer,"Empty");
int Result = EEPrint(buffer, x, Unit);
printf("%d %e \"%s\"\n", Result != Expect, x, buffer);
return Result != Expect;
}
int main() {
EEprint_Test(0, -1.0, 'R');
EEprint_Test(0, -0.0, 'R');
EEprint_Test(0, 0.0, 'R');
EEprint_Test(1,1.23e-30, 'R');
EEprint_Test(1,0.994999e-24, 'R');
EEprint_Test(0,0.995001e-24, 'R');
EEprint_Test(0,1.e-24, 'R');
EEprint_Test(0,1.23e-20, 'R');
EEprint_Test(0,1.23e-10, 'R');
EEprint_Test(0,1.23e-1, 'R');
EEprint_Test(0,1.23e0, 'R');
EEprint_Test(0,1.23e1, 'R');
EEprint_Test(0,1.23e2, 'R');
EEprint_Test(0,1.23e3, 'R');
EEprint_Test(0,1.23e4, 'R');
EEprint_Test(0,1.23e5, 'R');
EEprint_Test(0,1.23e10, 'R');
EEprint_Test(0,1.23e20, 'R');
EEprint_Test(0,9.94999e26, 'R');
EEprint_Test(1,9.95001e26, 'R');
EEprint_Test(1,1.23e30, 'R');
EEprint_Test(1,DBL_MAX, 'R');
EEprint_Test(1,0.0/0.0, 'R');
setlocale(LC_ALL,"it_IT"); // comma for DP
EEprint_Test(0,1.23e0, 'R');
return 0;
}
#if 0
0 -1.000000e+00 "-1R"
0 -0.000000e+00 "0R"
0 0.000000e+00 "0R"
0 1.230000e-30 "Empty"
0 9.949990e-25 "Empty"
0 9.950010e-25 "1y"
0 1.000000e-24 "1y"
0 1.230000e-20 "12z"
0 1.230000e-10 "120p"
0 1.230000e-01 "120m"
0 1.230000e+00 "1R2"
0 1.230000e+01 "12R"
0 1.230000e+02 "120R"
0 1.230000e+03 "1k2"
0 1.230000e+04 "12k"
0 1.230000e+05 "120k"
0 1.230000e+10 "12G"
0 1.230000e+20 "120E"
0 9.949990e+26 "990Y"
0 9.950010e+26 "Empty"
0 1.230000e+30 "Empty"
0 1.797693e+308 "Empty"
0 nan "Empty"
0 1,230000e+00 "1R2"
#endif