2011-10-25 3 views
1

エレクトロニクスアプリケーションのコンデンサ値を出力しています。業界標準の方法で値を2 s.fにフォーマットしたいと思います。例えば、4.7µF4u7になり、220nF220nになるなど、小数点の代わりにSIスカラー接頭辞が使用されます。エレガンスは、私が思い付くことができる最高のものは、この不器用な混乱で、私をエスケープしているようだ:printf用のエレガントなカスタム小数点(ロケールベースではありません)?

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

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 
+0

ありがとうございました。 TBH私はEEPrint機能が私のものより優れているかどうかはわかりません。 ... – damian

+0

入力がうまく行き渡っていて、uFまたはnFのために動作した場合、OPアプローチは確かに直接的で読みやすくなります。私は一般的な解決策(抵抗は通常スケールの反対側にあります)とすべてのFP値( - 、INF、NANなど)を扱うソリューションを見ていました。値が自然に2SFのときは、OPソリューションがうまく動作します(これはキャップの通常のケースです)。珍しい上限値では、.95 <= 'post' <= .99のときに>100μFと_fails_の値を持つ2 SFに常に丸めません。BTW:' printf( "%.0f%c \ n"シンボル) '。これがCの場合は、 'modf()'と 'modf()'を比較してください。うわー!これは2011年の投稿です! – chux

関連する問題