好吧,我结束了编写自己的函数。在 double 的所有范围内使用 gcc 和 tcc 进行测试,给出完全相同的输出(除了极少数非常小的值,小于 1E-319)
我发布它以防有人发现它有用。
爪哇:
/**
* Returns a double with an adhoc formatting, compatible with its C counterpart
*
* If the absolute value is not too small or too big (thresholdLow-thresholdHigh)
* the floating format is used, elsewhere the scientific.
* In addition
* - trailing zeros in fractional part are removed
* - if the value (or mantisa) is integer, a trailing .0 is always included
* - the exponent in sci notation is two or three digits
* - positive and negative zero returns "0.0"
* - special vals: "NaN" "Infinite" "-Infinite"
*
* Remember to set Locale.setDefault(Locale.US) in your program.
*
* @param v double
* @param formatFloat floating point format, suggested: "%.5f"
* @param formatSci scientific format, must use lowercase 'e' : "%.5e"
* @param thresholdLow
* @param thresholdHigh
* @return formatted string
*/
public static String sprintfDouble(double v, String formatFloat, String formatSci, double thresholdLow,
double thresholdHigh) {
if(v==0.0)
return "0.0"; //dont care about negative zero
if(Double.isInfinite(v) || Double.isNaN(v))
return String.format(formatFloat,v);
boolean neg = false;
if (v < 0) {
v = -v;
neg = true;
}
String e = "";
String res;
if (v > thresholdLow && v < thresholdHigh) {
res = String.format(formatFloat, v);
} else {
res = String.format(formatSci, v);
int sp = res.indexOf('e');
e = res.substring(sp);
res = res.substring(0, sp);
}
if (res.indexOf('.') < 0)
res += "."; // add decimal point if not present
res = res.replaceAll("0+$", ""); // trim trailing zeros
if (res.endsWith("."))
res += "0"; // add traiing zero if nec
res += e;
if (neg)
res = "-" + res;
return res;
}
public static String sprintfDouble5(double v){
return sprintfDouble(v, "%.5f","%.5e",0.01,1000000.0);
}
C:
char * sprintfDouble(char *buf, double v, const char *floatFormat, const char *sciFormat, double thresholdLow, double thresholdHigh) {
char *p;
char *pd; /* pointer to '.' */
char *pe; /* pd=, pe=pointer to 'e' (or null terminator) */
char *buforig;
int trimmed;
if(v != v) { /* nan */
sprintf(buf,"NaN");
return buf;
}
if(v == v && (v - v) != 0.0) { /* infinity */
sprintf(buf, v < 0 ? "-Infinity" :"Infinity");
return buf;
}
if(v==0) { /* positive or negative zero, dont distinguish*/
sprintf(buf, "0.0");
return buf;
}
buforig = buf;
if(v <0) {
v = -v;
buf[0] = '-';
buf++;
}
if( v > thresholdLow && v < thresholdHigh ) {
sprintf(buf,floatFormat, v);
pe = buf+strlen(buf);
pd = (char *) strchr(buf,'.');
if(pd == NULL) { /* no decimal point? add it */
pd = pe;
*pe++ = '.';
*pe++ = '0';
*pe = 0;
}
} else {
sprintf(buf,sciFormat, v);
pe = (char *)strchr(buf,'e');
pd = (char *)strchr(buf,'.');
if(pd ==NULL) { /* no decimal point with scientific notation? rare but... */
p= buf+ strlen(buf);
while(p>=pe) {
*p = *(p-2);
p--;
}
pd = pe;
*pe++ = '.';
*pe++ = '0';
*pe = 0;
}
/* three digits exponent with leading zero? trim it */
if( (*(pe+2) == '0' ) && ( strlen(buf) - (pe-buf))==5) {
*(pe+2)=*(pe+3);
*(pe+3)=*(pe+4);
*(pe+4)=*(pe+5);
}
} /* now trim trailing zeros */
trimmed = 0;
p=pe-1;
while(*p =='0' ) {
p--;
trimmed++;
}
if(*p=='.') {
trimmed--; // dont trim the zero after the decimal point
p++;
}
if(trimmed>0) {
p = pe;
while(1) {
*(p-trimmed) = *p;
if(*p==0) break;
p++;
}
}
return buforig;
}
char * sprintfDouble5(char *buf,double v) {
return sprintfDouble(buf, v, "%.5f", "%.5e", 0.01, 1000000.0);
}
测试代码。
爪哇
static void test() {
Locale.setDefault(Locale.US);
double start = 1.0;
double x=start;
for(int i=0;i<367;i++) {
System.out.println(sprintfDouble5(x));
x*= -7.0;
}
x=start;
for(int i=0;i<6;i++) {
System.out.println(sprintfDouble5(x));
x/= -5;
}
for(int i=0;i<200;i++) {
System.out.println(sprintfDouble5(x));
x/= -42.01;
}
x=Math.PI*0.0000001;
for(int i=0;i<20;i++) {
System.out.println(sprintfDouble5(x));
x*=10;
}
System.out.println(sprintfDouble5(0.0));
System.out.println(sprintfDouble5(-0.0));
System.out.println(sprintfDouble5(0.0/0.0));
}
C:
void test1() {
char buf[64];
double start,x;
int i;
start = 1.0;
x = start;
for(i=0;i<367;i++) {
printf("%s\n",sprintfDouble5(buf,x));
x *= -7.0;
}
x = start;
for(i=0;i<6;i++) {
printf("%s\n",sprintfDouble5(buf,x));
x /= -5;
}
for(i=0;i<200;i++) {
printf("%s\n",sprintfDouble5(buf,x));
x/= -42.01;
}
x = atan(1.0) * 4 * 0.0000001; /* PI */
for(i=0;i<20;i++) {
printf("%s\n",sprintfDouble5(buf,x));
x *= 10;
}
printf("%s\n",sprintfDouble5(buf,0.0));
printf("%s\n",sprintfDouble5(buf,-0.0));
printf("%s\n",sprintfDouble5(buf,0.0/0.0));
}