version bump 0.5.1: more fixes needed for xls

- Updated frac to 0.3.1 (issue with numbers exceeding 2**32)
- Invalid dates render empty string
- Sub-second string format
- First steps towards Engineering format
- Fraction formats don't render blanks in the case of zero
- Trailing spaces removed
- More implied tests
This commit is contained in:
SheetJS 2014-01-12 03:31:44 -05:00
parent d31879d702
commit c299585bfb
5 changed files with 826 additions and 101 deletions

View File

@ -1,13 +1,14 @@
{
"name": "ssf",
"version": "0.5.0",
"version": "0.5.1",
"author": "SheetJS",
"description": "pure-JS library to format data using ECMA-376 spreadsheet Format Codes",
"keywords": [ "format", "sprintf", "spreadsheet" ],
"main": "ssf.js",
"dependencies": {
"voc":"",
"colors":""
"colors":"",
"frac":"0.3.1"
},
"devDependencies": {
"mocha":""

43
ssf.js
View File

@ -70,9 +70,9 @@ var frac = function frac(x, D, mixed) {
var B = x * sgn;
var P_2 = 0, P_1 = 1, P = 0;
var Q_2 = 1, Q_1 = 0, Q = 0;
var A = B|0;
var A = Math.floor(B);
while(Q_1 < D) {
A = B|0;
A = Math.floor(B);
P = A * P_1 + P_2;
Q = A * Q_1 + Q_2;
if((B - A) < 0.0000000005) break;
@ -83,6 +83,7 @@ var frac = function frac(x, D, mixed) {
if(Q > D) { Q = Q_1; P = P_1; }
if(Q > D) { Q = Q_2; P = P_2; }
if(!mixed) return [0, sgn * P, Q];
if(Q==0) throw "Unexpected state: "+P+" "+P_1+" "+P_2+" "+Q+" "+Q_1+" "+Q_2;
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
};
@ -96,13 +97,13 @@ var general_fmt = function(v) {
else if(V >= 0.0001 && V < 0.001) o = v.toPrecision(6);
else if(V >= Math.pow(10,10) && V < Math.pow(10,11)) o = v.toFixed(10).substr(0,12);
else if(V > Math.pow(10,-9) && V < Math.pow(10,11)) {
o = v.toFixed(12).replace(/(\.[0-9]*[1-9])0*$/,"$1").replace(/\.$/,"");
o = v.toFixed(12).replace(/(\.[0-9]*[1-9])0*$/,"$1").replace(/\.$/,"");
if(o.length > 11+(v<0?1:0)) o = v.toPrecision(10);
if(o.length > 11+(v<0?1:0)) o = v.toExponential(5);
}
}
else {
o = v.toFixed(11).replace(/(\.[0-9]*[1-9])0*$/,"$1");
if(o.length > 11 + (v<0?1:0)) o = v.toPrecision(6);
if(o.length > 11 + (v<0?1:0)) o = v.toPrecision(6);
}
o = o.replace(/(\.[0-9]*[1-9])0+e/,"$1e").replace(/\.0*e/,"e");
return o.replace("e","E").replace(/\.0*$/,"").replace(/\.([0-9]*[^0])0*$/,".$1").replace(/(E[+-])([0-9])$/,"$1"+"0"+"$2");
@ -112,9 +113,10 @@ var general_fmt = function(v) {
};
SSF._general = general_fmt;
var parse_date_code = function parse_date_code(v,opts) {
var date = Math.floor(v), time = Math.round(86400 * (v - date)), dow=0;
var date = Math.floor(v), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[], out={D:date, T:time, u:86400*(v-date)-time}; fixopts(opts = (opts||{}));
if(opts.date1904) date += 1462;
if(date > 2958465) return null;
if(date === 60) {dout = [1900,2,29]; dow=3;}
else if(date === 0) {dout = [1900,1,0]; dow=6;}
else {
@ -173,8 +175,8 @@ var write_date = function(type, fmt, val) {
} break;
case 's': switch(fmt) { /* seconds */
case 's': return val.S;
case 'ss': return pad(val.S, 2);
case 'ss.0': return pad(val.S,2) + "." + Math.round(10*val.u);
case 'ss': return pad(Math.round(val.S+val.u), 2);
case 'ss.0': var o = pad(Math.round(10*(val.S+val.u)),3); return o.substr(0,2)+"." + o.substr(2);
default: throw 'bad second format: ' + fmt;
} break;
case 'Z': switch(fmt) {
@ -201,8 +203,14 @@ var write_num = function(type, fmt, val) {
if(fmt.indexOf("E") > -1) {
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
if(fmt == '##0.0E+0') {
var ee = Number(val.toExponential(0).substr(3))%3;
o = (val/Math.pow(10,ee%3)).toPrecision(idx+1+(ee%3)).replace(/^([+-]?)([0-9]*)\.([0-9]*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,ee) + "." + $3.substr(ee) + "E"; });
var ee = (Number(val.toExponential(0).substr(2+(val<0))))%3;
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(3+ee)%3);
if(!o.match(/[Ee]/)) {
var fakee = (Number(val.toExponential(0).substr(2+(val<0))));
if(o.indexOf(".") === -1) o = o[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
else throw "missing E";
}
o = o.replace(/^([+-]?)([0-9]*)\.([0-9]*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(3+ee)%3) + "." + $3.substr(ee) + "E"; });
} else o = val.toExponential(idx);
if(fmt.match(/E\+00$/) && o.match(/e[+-][0-9]$/)) o = o.substr(0,o.length-1) + "0" + o[o.length-1];
if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
@ -226,9 +234,9 @@ var write_num = function(type, fmt, val) {
case "#,##0": return sign + commaify(String(Math.round(aval)));
case "#,##0.0": r = Math.round((val-Math.floor(val))*10); return val < 0 ? "-" + write_num(type, fmt, -val) : commaify(String(Math.floor(val))) + "." + r;
case "#,##0.00": r = Math.round((val-Math.floor(val))*100); return val < 0 ? "-" + write_num(type, fmt, -val) : commaify(String(Math.floor(val))) + "." + (r < 10 ? "0"+r:r);
case "# ? / ?": ff = frac(aval, 9, true); return sign + (ff[0]||"") + " " + (ff[1] === 0 ? " " : ff[1] + "/" + ff[2]);
case "# ?? / ??": ff = frac(aval, 99, true); return sign + (ff[0]||"") + " " + (ff[1] ? pad(ff[1],2," ") + "/" + rpad(ff[2],2," ") : " ");
case "# ??? / ???": ff = frac(aval, 999, true); return sign + (ff[0]||"") + " " + (ff[1] ? pad(ff[1],3," ") + "/" + rpad(ff[2],3," ") : " ");
case "# ? / ?": ff = frac(aval, 9, true); return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] === 0 ? " " : ff[1] + "/" + ff[2]);
case "# ?? / ??": ff = frac(aval, 99, true); return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad(ff[1],2," ") + "/" + rpad(ff[2],2," ") : " ");
case "# ??? / ???": ff = frac(aval, 999, true); return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad(ff[1],3," ") + "/" + rpad(ff[2],3," ") : " ");
default:
}
throw new Error("unsupported format |" + fmt + "|");
@ -268,6 +276,7 @@ function eval_fmt(fmt, v, opts, flen) {
case 'm': case 'd': case 'y': case 'h': case 's': case 'e':
if(v < 0) return "";
if(!dt) dt = parse_date_code(v, opts);
if(!dt) return "";
o = fmt[i]; while(fmt[++i] === c) o+=c;
if(c === 's' && fmt[i] === '.' && fmt[i+1] === '0') { o+='.'; while(fmt[++i] === '0') o+= '0'; }
if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; /* m = minute */
@ -275,6 +284,7 @@ function eval_fmt(fmt, v, opts, flen) {
q={t:c, v:o}; out.push(q); lst = c; break;
case 'A':
if(!dt) dt = parse_date_code(v, opts);
if(!dt) return "";
q={t:c,v:"A"};
if(fmt.substr(i, 3) === "A/P") {q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
else if(fmt.substr(i,5) === "AM/PM") { q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
@ -323,17 +333,16 @@ function eval_fmt(fmt, v, opts, flen) {
out[i].t = 't'; break;
case 'n': case '(':
var jj = i+1;
while(out[jj] && ("? D".indexOf(out[jj].t) > -1 || out[i].t == '(' && (out[jj].t == ')' || out[jj].t == 'n') || out[jj].t == 't' && (out[jj].v == '/' || out[jj].v == '$' || (out[jj].v == ' ' && (out[jj+1]||{}).t == '?')))) {
while(out[jj] && ("?D".indexOf(out[jj].t) > -1 || (out[jj].t == " " && (out[jj+1]||{}).t === "?" ) || out[i].t == '(' && (out[jj].t == ')' || out[jj].t == 'n') || out[jj].t == 't' && (out[jj].v == '/' || out[jj].v == '$' || (out[jj].v == ' ' && (out[jj+1]||{}).t == '?')))) {
if(out[jj].v!==' ') out[i].v += ' ' + out[jj].v;
delete out[jj]; ++jj;
}
out[i].v = write_num(out[i].t, out[i].v, v);
out[i].t = 't';
i = jj; break;
i = jj-1; break;
default: throw "unrecognized type " + out[i].t;
}
}
return out.map(function(x){return x.v;}).join("");
}
SSF._eval = eval_fmt;
@ -364,7 +373,7 @@ SSF._table = table_fmt;
SSF.load = function(fmt, idx) { table_fmt[idx] = fmt; };
SSF.format = format;
SSF.get_table = function() { return table_fmt; };
SSF.load_table = function(tbl) { for(var i=0; i!=0x0188; ++i) if(table_fmt[i]) SSF.load(i, table_fmt[i]); };
SSF.load_table = function(tbl) { for(var i=0; i!=0x0188; ++i) if(tbl[i]) SSF.load(tbl[i], i); };
};
make_ssf(SSF);
if(typeof module !== 'undefined' && typeof DO_NOT_EXPORT_SSF === 'undefined') module.exports = SSF;

69
ssf.md
View File

@ -146,13 +146,13 @@ For numbers, try to display up to 11 digits of the number (the original code
else if(V >= 0.0001 && V < 0.001) o = v.toPrecision(6);
else if(V >= Math.pow(10,10) && V < Math.pow(10,11)) o = v.toFixed(10).substr(0,12);
else if(V > Math.pow(10,-9) && V < Math.pow(10,11)) {
o = v.toFixed(12).replace(/(\.[0-9]*[1-9])0*$/,"$1").replace(/\.$/,"");
o = v.toFixed(12).replace(/(\.[0-9]*[1-9])0*$/,"$1").replace(/\.$/,"");
if(o.length > 11+(v<0?1:0)) o = v.toPrecision(10);
if(o.length > 11+(v<0?1:0)) o = v.toExponential(5);
}
}
else {
o = v.toFixed(11).replace(/(\.[0-9]*[1-9])0*$/,"$1");
if(o.length > 11 + (v<0?1:0)) o = v.toPrecision(6);
if(o.length > 11 + (v<0?1:0)) o = v.toPrecision(6);
}
o = o.replace(/(\.[0-9]*[1-9])0+e/,"$1e").replace(/\.0*e/,"e");
return o.replace("e","E").replace(/\.0*$/,"").replace(/\.([0-9]*[^0])0*$/,".$1").replace(/(E[+-])([0-9])$/,"$1"+"0"+"$2");
@ -262,7 +262,7 @@ portion of a 24 hour day).
```js>tmp/50_date.js
var parse_date_code = function parse_date_code(v,opts) {
var date = Math.floor(v), time = Math.round(86400 * (v - date)), dow=0;
var date = Math.floor(v), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[], out={D:date, T:time, u:86400*(v-date)-time}; fixopts(opts = (opts||{}));
```
@ -273,6 +273,12 @@ shifted by 1462 days.
if(opts.date1904) date += 1462;
```
Date codes beyond 12/31/9999 are invalid:
```
if(date > 2958465) return null;
```
Due to a bug in Lotus 1-2-3 which was propagated by Excel and other variants,
the year 1900 is recognized as a leap year. JS has no way of representing that
abomination as a `Date`, so the easiest way is to store the data as a tuple.
@ -359,8 +365,19 @@ For the special case of engineering notation, "shift" the decimal:
```
if(fmt == '##0.0E+0') {
var ee = Number(val.toExponential(0).substr(3))%3;
o = (val/Math.pow(10,ee%3)).toPrecision(idx+1+(ee%3)).replace(/^([+-]?)([0-9]*)\.([0-9]*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,ee) + "." + $3.substr(ee) + "E"; });
var ee = (Number(val.toExponential(0).substr(2+(val<0))))%3;
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(3+ee)%3);
if(!o.match(/[Ee]/)) {
```
TODO: something reasonable
```
var fakee = (Number(val.toExponential(0).substr(2+(val<0))));
if(o.indexOf(".") === -1) o = o[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
else throw "missing E";
}
o = o.replace(/^([+-]?)([0-9]*)\.([0-9]*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(3+ee)%3) + "." + $3.substr(ee) + "E"; });
} else o = val.toExponential(idx);
if(fmt.match(/E\+00$/) && o.match(/e[+-][0-9]$/)) o = o.substr(0,o.length-1) + "0" + o[o.length-1];
if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
@ -404,9 +421,9 @@ The default cases are hard-coded. TODO: actually parse them
The frac helper function is used for fraction formats (defined below).
```js>tmp/60_number.js
case "# ? / ?": ff = frac(aval, 9, true); return sign + (ff[0]||"") + " " + (ff[1] === 0 ? " " : ff[1] + "/" + ff[2]);
case "# ?? / ??": ff = frac(aval, 99, true); return sign + (ff[0]||"") + " " + (ff[1] ? pad(ff[1],2," ") + "/" + rpad(ff[2],2," ") : " ");
case "# ??? / ???": ff = frac(aval, 999, true); return sign + (ff[0]||"") + " " + (ff[1] ? pad(ff[1],3," ") + "/" + rpad(ff[2],3," ") : " ");
case "# ? / ?": ff = frac(aval, 9, true); return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] === 0 ? " " : ff[1] + "/" + ff[2]);
case "# ?? / ??": ff = frac(aval, 99, true); return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad(ff[1],2," ") + "/" + rpad(ff[2],2," ") : " ");
case "# ??? / ???": ff = frac(aval, 999, true); return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad(ff[1],3," ") + "/" + rpad(ff[2],3," ") : " ");
default:
}
throw new Error("unsupported format |" + fmt + "|");
@ -474,6 +491,7 @@ Merge strings like "mmmmm" or "hh" into one block:
```
if(!dt) dt = parse_date_code(v, opts);
if(!dt) return "";
o = fmt[i]; while(fmt[++i] === c) o+=c;
```
@ -502,6 +520,7 @@ the HH/hh jazz. TODO: investigate this further.
```
case 'A':
if(!dt) dt = parse_date_code(v, opts);
if(!dt) return "";
q={t:c,v:"A"};
if(fmt.substr(i, 3) === "A/P") {q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
else if(fmt.substr(i,5) === "AM/PM") { q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
@ -539,7 +558,7 @@ number 123.456 under format `|??| / |???| |???| foo` is `|15432| / |125| | |
q={t:c, v:o}; out.push(q); lst = c; break;
```
Due to how the CSV generation works, asterisk characters are discarded. TODO:
Due to how the CSV generation works, asterisk characters are discarded. TODO:
communicate this somehow, possibly with an option
```
@ -591,17 +610,16 @@ The default magic characters are listed in subsubsections 18.8.30-31 of ECMA376:
out[i].t = 't'; break;
case 'n': case '(':
var jj = i+1;
while(out[jj] && ("? D".indexOf(out[jj].t) > -1 || out[i].t == '(' && (out[jj].t == ')' || out[jj].t == 'n') || out[jj].t == 't' && (out[jj].v == '/' || out[jj].v == '$' || (out[jj].v == ' ' && (out[jj+1]||{}).t == '?')))) {
while(out[jj] && ("?D".indexOf(out[jj].t) > -1 || (out[jj].t == " " && (out[jj+1]||{}).t === "?" ) || out[i].t == '(' && (out[jj].t == ')' || out[jj].t == 'n') || out[jj].t == 't' && (out[jj].v == '/' || out[jj].v == '$' || (out[jj].v == ' ' && (out[jj+1]||{}).t == '?')))) {
if(out[jj].v!==' ') out[i].v += ' ' + out[jj].v;
delete out[jj]; ++jj;
}
out[i].v = write_num(out[i].t, out[i].v, v);
out[i].t = 't';
i = jj; break;
i = jj-1; break;
default: throw "unrecognized type " + out[i].t;
}
}
return out.map(function(x){return x.v;}).join("");
}
SSF._eval = eval_fmt;
@ -655,8 +673,8 @@ var write_date = function(type, fmt, val) {
} break;
case 's': switch(fmt) { /* seconds */
case 's': return val.S;
case 'ss': return pad(val.S, 2);
case 'ss.0': return pad(val.S,2) + "." + Math.round(10*val.u);
case 'ss': return pad(Math.round(val.S+val.u), 2);
case 'ss.0': var o = pad(Math.round(10*(val.S+val.u)),3); return o.substr(0,2)+"." + o.substr(2);
default: throw 'bad second format: ' + fmt;
} break;
```
@ -731,11 +749,11 @@ SSF.load = function(fmt, idx) { table_fmt[idx] = fmt; };
SSF.format = format;
```
To support multiple SSF tables:
To support multiple SSF tables:
```
SSF.get_table = function() { return table_fmt; };
SSF.load_table = function(tbl) { for(var i=0; i!=0x0188; ++i) if(table_fmt[i]) SSF.load(i, table_fmt[i]); };
SSF.load_table = function(tbl) { for(var i=0; i!=0x0188; ++i) if(tbl[i]) SSF.load(tbl[i], i); };
```
## Fraction Library
@ -748,9 +766,9 @@ var frac = function frac(x, D, mixed) {
var B = x * sgn;
var P_2 = 0, P_1 = 1, P = 0;
var Q_2 = 1, Q_1 = 0, Q = 0;
var A = B|0;
var A = Math.floor(B);
while(Q_1 < D) {
A = B|0;
A = Math.floor(B);
P = A * P_1 + P_2;
Q = A * Q_1 + Q_2;
if((B - A) < 0.0000000005) break;
@ -761,6 +779,7 @@ var frac = function frac(x, D, mixed) {
if(Q > D) { Q = Q_1; P = P_1; }
if(Q > D) { Q = Q_2; P = P_2; }
if(!mixed) return [0, sgn * P, Q];
if(Q==0) throw "Unexpected state: "+P+" "+P_1+" "+P_2+" "+Q+" "+Q_1+" "+Q_2;
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
};
@ -818,14 +837,15 @@ test:
```json>package.json
{
"name": "ssf",
"version": "0.5.0",
"version": "0.5.1",
"author": "SheetJS",
"description": "pure-JS library to format data using ECMA-376 spreadsheet Format Codes",
"keywords": [ "format", "sprintf", "spreadsheet" ],
"main": "ssf.js",
"dependencies": {
"voc":"",
"colors":""
"colors":"",
"frac":"0.3.1"
},
"devDependencies": {
"mocha":""
@ -859,14 +879,17 @@ before_install:
The mocha test driver tests the implied formats:
```js>test/implied.js
/* vim: set ts=2: */
var SSF = require('../');
var fs = require('fs'), assert = require('assert');
var data = JSON.parse(fs.readFileSync('./test/implied.json','utf8'));
var skip = [];
function doit(d) {
d[1].forEach(function(r){if(!r[2])assert.equal(SSF.format(r[0],d[0]),r[1]);});
}
describe('implied formats', function() {
data.forEach(function(d) {
it(d[1]+" for "+d[0], skip.indexOf(d[1]) > -1 ? null : function(){
if(d.length == 2) it(d[0], function() { doit(d); });
else it(d[1]+" for "+d[0], skip.indexOf(d[1]) > -1 ? null : function(){
assert.equal(SSF.format(d[1], d[0], {}), d[2]);
});
});

View File

@ -1,11 +1,14 @@
/* vim: set ts=2: */
var SSF = require('../');
var fs = require('fs'), assert = require('assert');
var data = JSON.parse(fs.readFileSync('./test/implied.json','utf8'));
var skip = [];
function doit(d) {
d[1].forEach(function(r){if(!r[2])assert.equal(SSF.format(r[0],d[0]),r[1]);});
}
describe('implied formats', function() {
data.forEach(function(d) {
it(d[1]+" for "+d[0], skip.indexOf(d[1]) > -1 ? null : function(){
if(d.length == 2) it(d[0], function() { doit(d); });
else it(d[1]+" for "+d[0], skip.indexOf(d[1]) > -1 ? null : function(){
assert.equal(SSF.format(d[1], d[0], {}), d[2]);
});
});

View File

@ -1,67 +1,756 @@
[
[12345.6789, 0, "12345.6789"],
[12345.6789, 1, "12346"],
[12345.6789, 2, "12345.68"],
[12345.6789, 3, "12,346"],
[12345.6789, 4, "12,345.68"],
[12345.6789, 9, "1234568%"],
[12345.6789, 10, "1234567.89%"],
[12345.6789, 11, "1.23E+04"],
[12345.6789, 12, "12345 2/3"],
[12345.6789, 13, "12345 55/81"],
[12345.6789, 14, "10/18/33"],
[12345.6789, 15, "18-Oct-33"],
[12345.6789, 16, "18-Oct"],
[12345.6789, 17, "Oct-33"],
[12345.6789, 18, "4:17 PM"],
[12345.6789, 19, "4:17:37 PM"],
[12345.6789, 20, "16:17"],
[12345.6789, 21, "16:17:37"],
[12345.6789, 22, "10/18/33 16:17"],
[12345.6789, 37, "12,346"],
[12345.6789, 38, "12,346"],
[12345.6789, 39, "12,345.68"],
[12345.6789, 40, "12,345.68"],
[12345.6789, 45, "17:37"],
[12345.6789, 46, "296296:17:37"],
[12345.6789, 47, "1737.0"],
[12345.6789, 48, "12.3E+3"],
[12345.6789, 49, "12345.6789"],
[1234567890000, [
[0, "1.23457E+12", true],
[1, "1234567890000"],
[2, "1234567890000.00"],
[3, "1,234,567,890,000"],
[4, "1,234,567,890,000.00"],
[9, "123456789000000%"],
[10, "123456789000000.00%"],
[11, "1.23E+12"],
[12, "1234567890000 "],
[13, "1234567890000 "],
[14, ""],
[15, ""],
[16, ""],
[17, ""],
[18, ""],
[19, ""],
[20, ""],
[21, ""],
[22, ""],
[37, "1,234,567,890,000 "],
[38, "1,234,567,890,000 "],
[39, "1,234,567,890,000.00"],
[40, "1,234,567,890,000.00"],
[45, ""],
[46, ""],
[47, ""],
[48, "1.2E+12"],
[49, "1.23457E+12", true]
]],
[-12345.6789, 0, "-12345.6789"],
[-12345.6789, 1, "-12346"],
[-12345.6789, 2, "-12345.68"],
[-12345.6789, 3, "-12,346"],
[-12345.6789, 4, "-12,345.68"],
[-12345.6789, 9, "-1234568%"],
[-12345.6789, 10, "-1234567.89%"],
[-12345.6789, 11, "-1.23E+04"],
[-12345.6789, 12, "-12345 2/3"],
[-12345.6789, 13, "-12345 55/81"],
[-12345.6789, 14, ""],
[-12345.6789, 15, ""],
[-12345.6789, 16, ""],
[-12345.6789, 17, ""],
[-12345.6789, 18, ""],
[-12345.6789, 19, ""],
[-12345.6789, 20, ""],
[-12345.6789, 21, ""],
[-12345.6789, 22, ""],
[-12345.6789, 37, "(12,346)"],
[-12345.6789, 38, "(12,346)"],
[-12345.6789, 39, "(12,345.68)"],
[-12345.6789, 40, "(12,345.68)"],
[-12345.6789, 45, ""],
[-12345.6789, 46, ""],
[-12345.6789, 47, ""],
[-12345.6789, 48, "-12.3E+3"],
[-12345.6789, 49, "-12345.6789"],
[123456789000, [
[0, "1.23457E+11"],
[1, "123456789000"],
[2, "123456789000.00"],
[3, "123,456,789,000"],
[4, "123,456,789,000.00"],
[9, "12345678900000%"],
[10, "12345678900000.00%"],
[11, "1.23E+11"],
[12, "123456789000 "],
[13, "123456789000 "],
[14, ""],
[15, ""],
[16, ""],
[17, ""],
[18, ""],
[19, ""],
[20, ""],
[21, ""],
[22, ""],
[37, "123,456,789,000 "],
[38, "123,456,789,000 "],
[39, "123,456,789,000.00"],
[40, "123,456,789,000.00"],
[45, ""],
[46, ""],
[47, ""],
[48, "123.5E+9", true],
[49, "1.23457E+11", true]
]],
[12345678900, [
[0, "12345678900"],
[1, "12345678900"],
[2, "12345678900.00"],
[3, "12,345,678,900"],
[4, "12,345,678,900.00"],
[9, "1234567890000%"],
[10, "1234567890000.00%"],
[11, "1.23E+10"],
[12, "12345678900 "],
[13, "12345678900 "],
[14, ""],
[15, ""],
[16, ""],
[17, ""],
[18, ""],
[19, ""],
[20, ""],
[21, ""],
[22, ""],
[37, "12,345,678,900 "],
[38, "12,345,678,900 "],
[39, "12,345,678,900.00"],
[40, "12,345,678,900.00"],
[45, ""],
[46, ""],
[47, ""],
[48, "12.3E+9"],
[49, "12345678900"]
]],
[1234567890, [
[0, "1234567890"],
[1, "1234567890"],
[2, "1234567890.00"],
[3, "1,234,567,890"],
[4, "1,234,567,890.00"],
[9, "123456789000%"],
[10, "123456789000.00%"],
[11, "1.23E+09"],
[12, "1234567890 "],
[13, "1234567890 "],
[14, ""],
[15, ""],
[16, ""],
[17, ""],
[18, ""],
[19, ""],
[20, ""],
[21, ""],
[22, ""],
[37, "1,234,567,890 "],
[38, "1,234,567,890 "],
[39, "1,234,567,890.00"],
[40, "1,234,567,890.00"],
[45, ""],
[46, ""],
[47, ""],
[48, "1.2E+9"],
[49, "1234567890"]
]],
[123456789, [
[0, "123456789"],
[1, "123456789"],
[2, "123456789.00"],
[3, "123,456,789"],
[4, "123,456,789.00"],
[9, "12345678900%"],
[10, "12345678900.00%"],
[11, "1.23E+08"],
[12, "123456789 "],
[13, "123456789 "],
[14, ""],
[15, ""],
[16, ""],
[17, ""],
[18, ""],
[19, ""],
[20, ""],
[21, ""],
[22, ""],
[37, "123,456,789 "],
[38, "123,456,789 "],
[39, "123,456,789.00"],
[40, "123,456,789.00"],
[45, ""],
[46, ""],
[47, ""],
[48, "123.5E+6"],
[49, "123456789"]
]],
[12345678.9, [
[0, "12345678.9"],
[1, "12345679"],
[2, "12345678.90"],
[3, "12,345,679"],
[4, "12,345,678.90"],
[9, "1234567890%"],
[10, "1234567890.00%"],
[11, "1.23E+07"],
[12, "12345679 "],
[13, "12345678 9/10"],
[14, ""],
[15, ""],
[16, ""],
[17, ""],
[18, ""],
[19, ""],
[20, ""],
[21, ""],
[22, ""],
[37, "12,345,679 "],
[38, "12,345,679 "],
[39, "12,345,678.90"],
[40, "12,345,678.90"],
[45, ""],
[46, ""],
[47, ""],
[48, "12.3E+6"],
[49, "12345678.9"]
]],
[1234567.89, [
[0, "1234567.89"],
[1, "1234568"],
[2, "1234567.89"],
[3, "1,234,568"],
[4, "1,234,567.89"],
[9, "123456789%"],
[10, "123456789.00%"],
[11, "1.23E+06"],
[12, "1234567 8/9"],
[13, "1234567 8/9 "],
[14, "2/15/80"],
[15, "15-Feb-80"],
[16, "15-Feb"],
[17, "Feb-80"],
[18, "9:21 PM"],
[19, "9:21:36 PM"],
[20, "21:21"],
[21, "21:21:36"],
[22, "2/15/80 21:21"],
[37, "1,234,568 "],
[38, "1,234,568 "],
[39, "1,234,567.89"],
[40, "1,234,567.89"],
[45, "21:36"],
[46, "29629629:21:36"],
[47, "2136.0"],
[48, "1.2E+6"],
[49, "1234567.89"]
]],
[123456.789, [
[0, "123456.789"],
[1, "123457"],
[2, "123456.79"],
[3, "123,457"],
[4, "123,456.79"],
[9, "12345679%"],
[10, "12345678.90%"],
[11, "1.23E+05"],
[12, "123456 4/5"],
[13, "123456 15/19"],
[14, "1/3/38"],
[15, "3-Jan-38"],
[16, "3-Jan"],
[17, "Jan-38"],
[18, "6:56 PM"],
[19, "6:56:10 PM"],
[20, "18:56"],
[21, "18:56:10"],
[22, "1/3/38 18:56"],
[37, "123,457 "],
[38, "123,457 "],
[39, "123,456.79"],
[40, "123,456.79"],
[45, "56:10"],
[46, "2962962:56:10"],
[47, "5609.6"],
[48, "123.5E+3"],
[49, "123456.789"]
]],
[12345.6789, [
[0, "12345.6789"],
[1, "12346"],
[2, "12345.68"],
[3, "12,346"],
[4, "12,345.68"],
[9, "1234568%"],
[10, "1234567.89%"],
[11, "1.23E+04"],
[12, "12345 2/3"],
[13, "12345 55/81"],
[14, "10/18/33"],
[15, "18-Oct-33"],
[16, "18-Oct"],
[17, "Oct-33"],
[18, "4:17 PM"],
[19, "4:17:37 PM"],
[20, "16:17"],
[21, "16:17:37"],
[22, "10/18/33 16:17"],
[37, "12,346 "],
[38, "12,346 "],
[39, "12,345.68"],
[40, "12,345.68"],
[45, "17:37"],
[46, "296296:17:37"],
[47, "1737.0"],
[48, "12.3E+3"],
[49, "12345.6789"]
]],
[1234.56789, [
[0, "1234.56789"],
[1, "1235"],
[2, "1234.57"],
[3, "1,235"],
[4, "1,234.57"],
[9, "123457%"],
[10, "123456.79%"],
[11, "1.23E+03"],
[12, "1234 4/7"],
[13, "1234 46/81"],
[14, "5/18/03"],
[15, "18-May-03"],
[16, "18-May"],
[17, "May-03"],
[18, "1:37 PM"],
[19, "1:37:46 PM"],
[20, "13:37"],
[21, "13:37:46"],
[22, "5/18/03 13:37"],
[37, "1,235 "],
[38, "1,235 "],
[39, "1,234.57"],
[40, "1,234.57"],
[45, "37:46"],
[46, "29629:37:46"],
[47, "3745.7"],
[48, "1.2E+3"],
[49, "1234.56789"]
]],
[123.456789, [
[0, "123.456789"],
[1, "123"],
[2, "123.46"],
[3, "123"],
[4, "123.46"],
[9, "12346%"],
[10, "12345.68%"],
[11, "1.23E+02"],
[12, "123 1/2"],
[13, "123 37/81"],
[14, "5/2/00"],
[15, "2-May-00"],
[16, "2-May"],
[17, "May-00"],
[18, "10:57 AM"],
[19, "10:57:47 AM"],
[20, "10:57"],
[21, "10:57:47"],
[22, "5/2/00 10:57"],
[37, "123 "],
[38, "123 "],
[39, "123.46"],
[40, "123.46"],
[45, "57:47"],
[46, "2962:57:47"],
[47, "5746.6"],
[48, "123.5E+0", true],
[49, "123.456789"]
]],
[12.3456789, [
[0, "12.3456789"],
[1, "12"],
[2, "12.35"],
[3, "12"],
[4, "12.35"],
[9, "1235%"],
[10, "1234.57%"],
[11, "1.23E+01"],
[12, "12 1/3"],
[13, "12 28/81"],
[14, "1/12/00"],
[15, "12-Jan-00"],
[16, "12-Jan"],
[17, "Jan-00"],
[18, "8:17 AM"],
[19, "8:17:47 AM"],
[20, "8:17"],
[21, "8:17:47"],
[22, "1/12/00 8:17"],
[37, "12 "],
[38, "12 "],
[39, "12.35"],
[40, "12.35"],
[45, "17:47"],
[46, "296:17:47"],
[47, "1746.7"],
[48, "12.3E+0", true],
[49, "12.3456789"]
]],
[1.23456789, [
[0, "1.23456789"],
[1, "1"],
[2, "1.23"],
[3, "1"],
[4, "1.23"],
[9, "123%"],
[10, "123.46%"],
[11, "1.23E+00"],
[12, "1 1/4"],
[13, "1 19/81"],
[14, "1/1/00"],
[15, "1-Jan-00"],
[16, "1-Jan"],
[17, "Jan-00"],
[18, "5:37 AM"],
[19, "5:37:47 AM"],
[20, "5:37"],
[21, "5:37:47"],
[22, "1/1/00 5:37"],
[37, "1 "],
[38, "1 "],
[39, "1.23"],
[40, "1.23"],
[45, "37:47"],
[46, "29:37:47"],
[47, "3746.7"],
[48, "1.2E+0", true],
[49, "1.23456789"]
]],
[0.123456789, [
[0, "0.123456789"],
[1, "0"],
[2, "0.12"],
[3, "0"],
[4, "0.12"],
[9, "12%"],
[10, "12.35%"],
[11, "1.23E-01"],
[12, " 1/8"],
[13, " 10/81"],
[14, "1/0/00"],
[15, "0-Jan-00"],
[16, "0-Jan"],
[17, "Jan-00"],
[18, "2:57 AM"],
[19, "2:57:47 AM"],
[20, "2:57"],
[21, "2:57:47"],
[22, "1/0/00 2:57"],
[37, "0 "],
[38, "0 "],
[39, "0.12"],
[40, "0.12"],
[45, "57:47"],
[46, "2:57:47"],
[47, "5746.7"],
[48, "123.5E-3", true],
[49, "0.123456789", true]
]],
[0.0123456789, [
[0, "0.012345679"],
[1, "0"],
[2, "0.01"],
[3, "0"],
[4, "0.01"],
[9, "1%"],
[10, "1.23%"],
[11, "1.23E-02"],
[12, "0 "],
[13, " 1/81"],
[14, "1/0/00"],
[15, "0-Jan-00"],
[16, "0-Jan"],
[17, "Jan-00"],
[18, "12:17 AM"],
[19, "12:17:47 AM"],
[20, "0:17"],
[21, "0:17:47"],
[22, "1/0/00 0:17"],
[37, "0 "],
[38, "0 "],
[39, "0.01"],
[40, "0.01"],
[45, "17:47"],
[46, "0:17:47"],
[47, "1746.7"],
[48, "12.3E-3", true],
[49, "0.012345679", true]
]],
[0.00123456789, [
[0, "0.001234568"],
[1, "0"],
[2, "0.00"],
[3, "0"],
[4, "0.00"],
[9, "0%"],
[10, "0.12%"],
[11, "1.23E-03"],
[12, "0 "],
[13, "0 "],
[14, "1/0/00"],
[15, "0-Jan-00"],
[16, "0-Jan"],
[17, "Jan-00"],
[18, "12:01 AM"],
[19, "12:01:47 AM"],
[20, "0:01"],
[21, "0:01:47"],
[22, "1/0/00 0:01"],
[37, "0 "],
[38, "0 "],
[39, "0.00"],
[40, "0.00"],
[45, "01:47"],
[46, "0:01:47"],
[47, "0146.7"],
[48, "1.2E-3", true],
[49, "0.001234568", true]
]],
[0.000123456789, [
[0, "0.000123457"],
[1, "0"],
[2, "0.00"],
[3, "0"],
[4, "0.00"],
[9, "0%"],
[10, "0.01%"],
[11, "1.23E-04"],
[12, "0 "],
[13, "0 "],
[14, "1/0/00"],
[15, "0-Jan-00"],
[16, "0-Jan"],
[17, "Jan-00"],
[18, "12:00 AM"],
[19, "12:00:11 AM"],
[20, "0:00"],
[21, "0:00:11"],
[22, "1/0/00 0:00"],
[37, "0 "],
[38, "0 "],
[39, "0.00"],
[40, "0.00"],
[45, "00:11"],
[46, "0:00:11"],
[47, "0010.7"],
[48, "123.5E-6", true],
[49, "0.000123457", true]
]],
[0.0000123456789, [
[0, "1.23457E-05"],
[1, "0"],
[2, "0.00"],
[3, "0"],
[4, "0.00"],
[9, "0%"],
[10, "0.00%"],
[11, "1.23E-05"],
[12, "0 "],
[13, "0 "],
[14, "1/0/00"],
[15, "0-Jan-00"],
[16, "0-Jan"],
[17, "Jan-00"],
[18, "12:00 AM"],
[19, "12:00:01 AM"],
[20, "0:00"],
[21, "0:00:01"],
[22, "1/0/00 0:00"],
[37, "0 "],
[38, "0 "],
[39, "0.00"],
[40, "0.00"],
[45, "00:01"],
[46, "0:00:01"],
[47, "0001.1"],
[48, "12.3E-6", true],
[49, "1.23457E-05", true]
]],
[0.00000123456789, [
[0, "1.23457E-06"],
[1, "0"],
[2, "0.00"],
[3, "0"],
[4, "0.00"],
[9, "0%"],
[10, "0.00%"],
[11, "1.23E-06"],
[12, "0 "],
[13, "0 "],
[14, "1/0/00"],
[15, "0-Jan-00"],
[16, "0-Jan"],
[17, "Jan-00"],
[18, "12:00 AM"],
[19, "12:00:00 AM"],
[20, "0:00"],
[21, "0:00:00"],
[22, "1/0/00 0:00"],
[37, "0 "],
[38, "0 "],
[39, "0.00"],
[40, "0.00"],
[45, "00:00"],
[46, "0:00:00"],
[47, "0000.1"],
[48, "1.2E-6", true],
[49, "1.23457E-06", true]
]],
[0.000000123456789, [
[0, "1.23457E-07"],
[1, "0"],
[2, "0.00"],
[3, "0"],
[4, "0.00"],
[9, "0%"],
[10, "0.00%"],
[11, "1.23E-07"],
[12, "0 "],
[13, "0 "],
[14, "1/0/00"],
[15, "0-Jan-00"],
[16, "0-Jan"],
[17, "Jan-00"],
[18, "12:00 AM"],
[19, "12:00:00 AM"],
[20, "0:00"],
[21, "0:00:00"],
[22, "1/0/00 0:00"],
[37, "0 "],
[38, "0 "],
[39, "0.00"],
[40, "0.00"],
[45, "00:00"],
[46, "0:00:00"],
[47, "0000.0"],
[48, "123.5E-9", true],
[49, "1.23457E-07", true]
]],
[0.0000000123456789, [
[0, "1.23457E-08"],
[1, "0"],
[2, "0.00"],
[3, "0"],
[4, "0.00"],
[9, "0%"],
[10, "0.00%"],
[11, "1.23E-08"],
[12, "0 "],
[13, "0 "],
[14, "1/0/00"],
[15, "0-Jan-00"],
[16, "0-Jan"],
[17, "Jan-00"],
[18, "12:00 AM"],
[19, "12:00:00 AM"],
[20, "0:00"],
[21, "0:00:00"],
[22, "1/0/00 0:00"],
[37, "0 "],
[38, "0 "],
[39, "0.00"],
[40, "0.00"],
[45, "00:00"],
[46, "0:00:00"],
[47, "0000.0"],
[48, "12.3E-9", true],
[49, "1.23457E-08", true]
]],
[0.00000000123456789, [
[0, "1.23457E-09"],
[1, "0"],
[2, "0.00"],
[3, "0"],
[4, "0.00"],
[9, "0%"],
[10, "0.00%"],
[11, "1.23E-09"],
[12, "0 "],
[13, "0 "],
[14, "1/0/00"],
[15, "0-Jan-00"],
[16, "0-Jan"],
[17, "Jan-00"],
[18, "12:00 AM"],
[19, "12:00:00 AM"],
[20, "0:00"],
[21, "0:00:00"],
[22, "1/0/00 0:00"],
[37, "0 "],
[38, "0 "],
[39, "0.00"],
[40, "0.00"],
[45, "00:00"],
[46, "0:00:00"],
[47, "0000.0"],
[48, "1.2E-9", true],
[49, "1.23457E-09", true]
]],
[0.000000000123456789, [
[0, "1.23457E-10"],
[1, "0"],
[2, "0.00"],
[3, "0"],
[4, "0.00"],
[9, "0%"],
[10, "0.00%"],
[11, "1.23E-10"],
[12, "0 "],
[13, "0 "],
[14, "1/0/00"],
[15, "0-Jan-00"],
[16, "0-Jan"],
[17, "Jan-00"],
[18, "12:00 AM"],
[19, "12:00:00 AM"],
[20, "0:00"],
[21, "0:00:00"],
[22, "1/0/00 0:00"],
[37, "0 "],
[38, "0 "],
[39, "0.00"],
[40, "0.00"],
[45, "00:00"],
[46, "0:00:00"],
[47, "0000.0"],
[48, "123.5E-12", true],
[49, "1.23457E-10", true]
]],
[-12345.6789, [
[0, "-12345.6789"],
[1, "-12346"],
[2, "-12345.68"],
[3, "-12,346"],
[4, "-12,345.68"],
[9, "-1234568%"],
[10, "-1234567.89%"],
[11, "-1.23E+04"],
[12, "-12345 2/3"],
[13, "-12345 55/81"],
[14, ""],
[15, ""],
[16, ""],
[17, ""],
[18, ""],
[19, ""],
[20, ""],
[21, ""],
[22, ""],
[37, "(12,346)"],
[38, "(12,346)"],
[39, "(12,345.68)"],
[40, "(12,345.68)"],
[45, ""],
[46, ""],
[47, ""],
[48, "-12.3E+3"],
[49, "-12345.6789"]
]],
[11.666666666666666, 0, "11.66666667"],
[5.057996968497839, 0, "5.057996968"],
[4.380353866983808, 0, "4.380353867"],
[12.333333333333343, 0, "12.33333333"],
[-0.000006211546860868111, 0, "-6.21155E-06"],
[12345.67876, 47, "1724.9"],
[0, 0, "0"]
]