Add function to round to even / preference to change default rounding used by JMP (to my understanding both Python and R follow IEEE 754 and round to even by default). Also add Teaching Script to demonstrate the effect of rounding to even vs rounding to nearest. To my understanding round-to-even is the default behaviour for example in IEEE 754 - Rounding Rules (wikipedia.org) Rounding to nearest should reduce bias when calculating aggregated statistics such as sum and mean from rounded values.
Below is example script (might not be the best demonstration...):
Names Default To Here(1);
// https://en.wikipedia.org/wiki/IEEE_754#Rounding_rules
// https://blogs.sas.com/content/iml/2019/11/11/round-to-even.html
// https://stackoverflow.com/questions/311696/why-does-net-use-bankers-rounding-as-default
row_count = 400;
dt = New Table("Bankers_demo", Add Rows(row_count), New Column("TrueValue", Numeric, Continuous, Formula(0.25 * (Row() - 100))));
dt << New Column("RoundToNearest", Numeric, Continuous, Formula(Round(:TrueValue, 0)));
dt << New Column("RoundToEven",
Numeric,
Continuous,
Formula(
l = Words(Char(:TrueValue), ".");
If(N Items(l) == 1,
:TrueValue,
If(l[2] == "5",
If(Modulo(Num(l[1]), 2),
Ceiling(:TrueValue),
Floor(:TrueValue)
),
Round(:TrueValue, 0)
)
);
)
);
dt << New Column("TrueSum", Numeric, Continuous, Formula(Col Cumulative Sum(:TrueValue)));
dt << New Column("NearestSum", Numeric, Continuous, Formula(Col Cumulative Sum(:RoundToNearest)));
dt << New Column("EvenSum", Numeric, Continuous, Formula(Col Cumulative Sum(:RoundToEven)));
dt << New Column("ErrorNearest", Numeric, Continuous, Formula(Abs(:TrueSum - :NearestSum)));
dt << New Column("ErrorEven", Numeric, Continuous, Formula(Abs(:TrueSum - :EvenSum)));
dt << New Column("TrueAvg", Numeric, Continuous, Formula(:TrueSum / Row()));
dt << New Column("NearestAvg", Numeric, Continuous, Formula(:NearestSum / Row()));
dt << New Column("EvenAvg", Numeric, Continuous, Formula(:EvenSum / Row()));
nw = New Window("Rounding",
H List Box(
Panel Box("Actions",
Button Box("Add Row", dt << Add Rows(1, At End)),
Button Box("Add 10 Rows", dt << Add Rows(10, At End)),
Button Box("Add 100 Rows", dt << Add Rows(100, At End)),
Button Box("Add 1000 Rows", dt << Add Rows(1000, At End))
),
gb = dt << Graph Builder(
Size(528, 456),
Show Control Panel(0),
Variables(X(:TrueValue), Y(:ErrorNearest, Position(1)), Y(:ErrorEven, Position(1))),
Elements(Points(X, Y(1), Y(2), Y(3), Legend(3)), Line(X, Y(1), Y(2), Y(3), Legend(5))),
Local Data Filter(Add Filter(columns(:TrueValue))),
SendToReport(
Dispatch(
{},
"400",
ScaleBox,
{Legend Model(
3,
Base(0, 0, 0, Item ID("TrueSum", 1)),
Base(1, 0, 0, Item ID("NearestSum", 1)),
Base(2, 0, 0, Item ID("EvenSum", 1))
)}
)
)
),
Tabulate(
Show Control Panel(0),
Add Table(Column Table(Statistics(Sum, Mean)), Row Table(Analysis Columns(:TrueValue, :RoundToNearest, :RoundToEven)))
)
),
<< On Close(Try(Close(dt, No Save)))
);