From 5f556004a271f9c0a6cc7589d2f77d6511429bd7 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 6 Feb 2019 14:04:18 +0100 Subject: [PATCH] Fix bugs in Number.prototype.toFixed and toExponential. toPrecision does not behave correctly: it doesn't pad the number with trailing zeroes to reach the desired precision. --- jsnumber.c | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/jsnumber.c b/jsnumber.c index 5915bd6..15c26e8 100644 --- a/jsnumber.c +++ b/jsnumber.c @@ -116,44 +116,61 @@ static void Np_toString(js_State *J) static void numtostr(js_State *J, const char *fmt, int w, double n) { char buf[32], *e; - if (isnan(n)) js_pushliteral(J, "NaN"); - else if (isinf(n)) js_pushliteral(J, n < 0 ? "-Infinity" : "Infinity"); - else if (n == 0) js_pushliteral(J, "0"); - else { - if (w < 1) w = 1; - if (w > 17) w = 17; - sprintf(buf, fmt, w, n); - e = strchr(buf, 'e'); - if (e) { - int exp = atoi(e+1); - sprintf(e, "e%+d", exp); - } - js_pushstring(J, buf); + sprintf(buf, fmt, w, n); + e = strchr(buf, 'e'); + if (e) { + int exp = atoi(e+1); + sprintf(e, "e%+d", exp); } + js_pushstring(J, buf); } static void Np_toFixed(js_State *J) { js_Object *self = js_toobject(J, 0); int width = js_tointeger(J, 1); + char buf[32]; + double x; if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); - numtostr(J, "%.*f", width, self->u.number); + if (width < 0) js_rangeerror(J, "precision %d out of range", width); + if (width > 20) js_rangeerror(J, "precision %d out of range", width); + x = self->u.number; + if (isnan(x) || isinf(x) || x <= -1e21 || x >= 1e21) + js_pushstring(J, jsV_numbertostring(J, buf, x)); + else + numtostr(J, "%.*f", width, x); } static void Np_toExponential(js_State *J) { js_Object *self = js_toobject(J, 0); int width = js_tointeger(J, 1); + char buf[32]; + double x; if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); - numtostr(J, "%.*e", width, self->u.number); + if (width < 0) js_rangeerror(J, "precision %d out of range", width); + if (width > 20) js_rangeerror(J, "precision %d out of range", width); + x = self->u.number; + if (isnan(x) || isinf(x)) + js_pushstring(J, jsV_numbertostring(J, buf, x)); + else + numtostr(J, "%.*e", width, self->u.number); } static void Np_toPrecision(js_State *J) { js_Object *self = js_toobject(J, 0); int width = js_tointeger(J, 1); + char buf[32]; + double x; if (self->type != JS_CNUMBER) js_typeerror(J, "not a number"); - numtostr(J, "%.*g", width, self->u.number); + if (width < 1) js_rangeerror(J, "precision %d out of range", width); + if (width > 21) js_rangeerror(J, "precision %d out of range", width); + x = self->u.number; + if (isnan(x) || isinf(x)) + js_pushstring(J, jsV_numbertostring(J, buf, x)); + else + numtostr(J, "%.*g", width, self->u.number); } void jsB_initnumber(js_State *J)