/* ToString() on a number */ const char *jsV_numbertostring(js_State *J, char buf[32], double f) { char digits[32], *p = buf, *s = digits; int exp, ndigits, point; if (f == 0) return "0"; if (isnan(f)) return "NaN"; if (isinf(f)) return f < 0 ? "-Infinity" : "Infinity"; /* Fast case for integers. This only works assuming all integers can be * exactly represented by a float. This is true for 32-bit integers and * 64-bit floats. */ if (f >= INT_MIN && f <= INT_MAX) { int i = (int)f; if ((double)i == f) return js_itoa(buf, i); } ndigits = js_grisu2(f, digits, &exp); point = ndigits + exp; if (signbit(f)) *p++ = '-'; if (point < -5 || point > 21) { *p++ = *s++; if (ndigits > 1) { int n = ndigits - 1; *p++ = '.'; while (n--) *p++ = *s++; } js_fmtexp(p, point - 1); } else if (point <= 0) { *p++ = '0'; *p++ = '.'; while (point++ < 0) *p++ = '0'; while (ndigits-- > 0) *p++ = *s++; *p = 0; } else { while (ndigits-- > 0) { *p++ = *s++; if (--point == 0 && ndigits > 0) *p++ = '.'; } while (point-- > 0) *p++ = '0'; *p = 0; } return buf; }
/* ToString() on a number */ const char *jsV_numbertostring(js_State *J, char buf[32], double f) { char digits[32], *p = buf, *s = digits; int exp, neg, ndigits, point; if (isnan(f)) return "NaN"; if (isinf(f)) return f < 0 ? "-Infinity" : "Infinity"; if (f == 0) return "0"; js_dtoa(f, digits, &exp, &neg, &ndigits); point = ndigits + exp; if (neg) *p++ = '-'; if (point < -5 || point > 21) { *p++ = *s++; if (ndigits > 1) { int n = ndigits - 1; *p++ = '.'; while (n--) *p++ = *s++; } js_fmtexp(p, point - 1); } else if (point <= 0) { *p++ = '0'; *p++ = '.'; while (point++ < 0) *p++ = '0'; while (ndigits-- > 0) *p++ = *s++; *p = 0; } else { while (ndigits-- > 0) { *p++ = *s++; if (--point == 0 && ndigits > 0) *p++ = '.'; } while (point-- > 0) *p++ = '0'; *p = 0; } return buf; }
/* * compute decimal integer m, exp such that: * f = m*10^exp * m is as short as possible with losing exactness * assumes special cases (NaN, +Inf, -Inf) have been handled. */ void js_dtoa(double f, char *s, int *exp, int *neg, int *ns) { int c, d, e2, e, ee, i, ndigit, oerrno; char tmp[NSIGNIF+10]; double g; oerrno = errno; /* in case strtod smashes errno */ /* * make f non-negative. */ *neg = 0; if(f < 0) { f = -f; *neg = 1; } /* * must handle zero specially. */ if(f == 0){ *exp = 0; s[0] = '0'; s[1] = '\0'; *ns = 1; return; } /* * find g,e such that f = g*10^e. * guess 10-exponent using 2-exponent, then fine tune. */ frexp(f, &e2); e = (int)(e2 * .301029995664); g = f * pow10(-e); while(g < 1) { e--; g = f * pow10(-e); } while(g >= 10) { e++; g = f * pow10(-e); } /* * convert NSIGNIF digits as a first approximation. */ for(i=0; i<NSIGNIF; i++) { d = (int)g; s[i] = d+'0'; g = (g-d) * 10; } s[i] = 0; /* * adjust e because s is 314159... not 3.14159... */ e -= NSIGNIF-1; js_fmtexp(s+NSIGNIF, e); /* * adjust conversion until strtod(s) == f exactly. */ for(i=0; i<10; i++) { g = js_strtod(s, NULL); if(f > g) { if(xadd1(s, NSIGNIF)) { /* gained a digit */ e--; js_fmtexp(s+NSIGNIF, e); } continue; } if(f < g) { if(xsub1(s, NSIGNIF)) { /* lost a digit */ e++; js_fmtexp(s+NSIGNIF, e); } continue; } break; } /* * play with the decimal to try to simplify. */ /* * bump last few digits up to 9 if we can */ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) { c = s[i]; if(c != '9') { s[i] = '9'; g = js_strtod(s, NULL); if(g != f) { s[i] = c; break; } } } /* * add 1 in hopes of turning 9s to 0s */ if(s[NSIGNIF-1] == '9') { strcpy(tmp, s); ee = e; if(xadd1(tmp, NSIGNIF)) { ee--; js_fmtexp(tmp+NSIGNIF, ee); } g = js_strtod(tmp, NULL); if(g == f) { strcpy(s, tmp); e = ee; } } /* * bump last few digits down to 0 as we can. */ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) { c = s[i]; if(c != '0') { s[i] = '0'; g = js_strtod(s, NULL); if(g != f) { s[i] = c; break; } } } /* * remove trailing zeros. */ ndigit = NSIGNIF; while(ndigit > 1 && s[ndigit-1] == '0'){ e++; --ndigit; } s[ndigit] = 0; *exp = e; *ns = ndigit; errno = oerrno; }