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
ありがとうございました。 TBH私はEEPrint機能が私のものより優れているかどうかはわかりません。 ... – damian
入力がうまく行き渡っていて、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