ref: 5f556004a271f9c0a6cc7589d2f77d6511429bd7
parent: 28643e6afb0c4a59b361a190d96c952c1c78ac77
author: Tor Andersson <tor.andersson@artifex.com>
date: Wed Feb 6 09:04:18 EST 2019
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.
--- a/jsnumber.c
+++ b/jsnumber.c
@@ -116,20 +116,13 @@
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)
@@ -136,8 +129,16 @@
{
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)
@@ -144,8 +145,16 @@
{
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)
@@ -152,8 +161,16 @@
{
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)