Skip to content

Commit 53b2136

Browse files
Improve calculation of number of significant digits needed when converting floats to JSON
1 parent 00c7ffb commit 53b2136

File tree

2 files changed

+76
-19
lines changed

2 files changed

+76
-19
lines changed

plotly/plotly_aux/Test_m2json.m

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
classdef Test_m2json < matlab.unittest.TestCase
2+
methods (Test)
3+
function testInRange0to10(tc)
4+
values = 1 + (1:5) + 0.23456789;
5+
expected = "[2.235,3.235,4.235,5.235,6.235]";
6+
tc.verifyEqual(string(m2json(values)), expected);
7+
end
8+
9+
function test2dArrayInRange0to10(tc)
10+
values = 1 + (1:5) + (0:1)' + 0.23456789;
11+
expected = "[[2.235,3.235,4.235,5.235,6.235]," ...
12+
+ "[3.235,4.235,5.235,6.235,7.235]]";
13+
tc.verifyEqual(string(m2json(values)), expected);
14+
end
15+
16+
function testInRange1e6to1e5(tc)
17+
values = 1e-6 * (1 + (1:5) + 0.23456789);
18+
expected = "[2.235e-06,3.235e-06,4.235e-06,5.235e-06,6.235e-06]";
19+
tc.verifyEqual(string(m2json(values)), expected);
20+
end
21+
22+
function testInRange1e14Plus0to1(tc)
23+
values = 1e14 + (1:5) + 0.23456789;
24+
expected = "[100000000000001,100000000000002,100000000000003,100000000000004,100000000000005]";
25+
tc.verifyEqual(string(m2json(values)), expected);
26+
end
27+
28+
function testInRange1e14Plus1e7Plus0to1(tc)
29+
values = 1e14 + 1e7 + (1:5) + 0.23456789;
30+
expected = "[100000010000001,100000010000002,100000010000003,100000010000004,100000010000005]";
31+
tc.verifyEqual(string(m2json(values)), expected);
32+
end
33+
34+
function testLogScaledVariables(tc)
35+
values = 1e14 + 10.^(1:5) + 0.23456789;
36+
expected = "[1e+14,1.000000000001e+14,1.00000000001e+14,1.0000000001e+14,1.000000001e+14]";
37+
tc.verifyEqual(string(m2json(values)), expected);
38+
end
39+
40+
function testInRangeMinus10to0(tc)
41+
values = -(1 + (1:5) + 0.23456789);
42+
expected = "[-2.235,-3.235,-4.235,-5.235,-6.235]";
43+
tc.verifyEqual(string(m2json(values)), expected);
44+
end
45+
46+
function testInRangeMinus1e5toMinus1e6(tc)
47+
values = -1e-6 * (1 + (1:5) + 0.23456789);
48+
expected = "[-2.235e-06,-3.235e-06,-4.235e-06,-5.235e-06,-6.235e-06]";
49+
tc.verifyEqual(string(m2json(values)), expected);
50+
end
51+
52+
function testInRangeMinus1e14Plus0to1(tc)
53+
values = -1e14 + (1:5) + 0.23456789;
54+
expected = "[-99999999999998.8,-99999999999997.8,-99999999999996.8,-99999999999995.8,-99999999999994.8]";
55+
tc.verifyEqual(string(m2json(values)), expected);
56+
end
57+
end
58+
end

plotly/plotly_aux/m2json.m

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,23 @@
55
valstr = cell2json(val);
66
elseif isa(val, "numeric")
77
sz = size(val);
8-
if isa(val,"single")
9-
precision = "7";
10-
else
11-
precision = "15";
12-
end
13-
fmt = "%." + precision + "g,";
14-
if length(find(sz>1))>1 % 2D or higher array
15-
valstr = "";
8+
numDigits = 3 + ceil(clip(log10(double(max(abs(val),[],"all"))) ...
9+
- log10(double(range(val,"all"))),0,12));
10+
numDigits(~isfinite(numDigits)) = 7;
11+
fmt = sprintf("%%.%ig", numDigits);
12+
if sum(sz>1)>1 % 2D or higher array
13+
valsubstr = strings(1, sz(1));
1614
for i = 1:sz(1)
17-
valsubstr = sprintf(fmt, val(i,:));
18-
valsubstr = valsubstr(1:(end-1));
19-
valstr = valstr + ", [" + valsubstr + "]";
15+
formattedRowVal = arrayfun(@(x) sprintf(fmt, x), val(i,:));
16+
valsubstr(i) = strjoin(formattedRowVal, ",");
17+
valsubstr(i) = "[" + valsubstr(i) + "]";
2018
end
21-
valstr = valstr(3:end); % trail leading commas
19+
valstr = strjoin(valsubstr, ",");
2220
else
23-
valstr = [sprintf(fmt, val)];
24-
valstr = valstr(1:(end-1));
25-
end
26-
if length(val)>1
27-
valstr = "[" + valstr + "]";
28-
elseif isempty(val)
29-
valstr = "[]";
21+
valstr = arrayfun(@(x) sprintf(fmt, x), val);
22+
valstr = strjoin(valstr, ",");
3023
end
24+
valstr = "[" + valstr + "]";
3125
valstr = strrep(valstr,"-Inf", "null");
3226
valstr = strrep(valstr, "Inf", "null");
3327
valstr = strrep(valstr, "NaN", "null");
@@ -60,3 +54,8 @@
6054
warning("Failed to m2json encode class of type: %s", class(val));
6155
end
6256
end
57+
58+
function x = clip(x,lb,ub)
59+
x(x<lb) = lb;
60+
x(x>ub) = ub;
61+
end

0 commit comments

Comments
 (0)