[
{ "name": "nearest-rank 5th percentile of 15,20,35,40,50 is 15 (rank ceil 0.25 = 1)", "args": [[15, 20, 35, 40, 50], 5, "nearest-rank", 2], "expect": 15 },
{ "name": "nearest-rank 30th percentile is 20 (rank ceil 1.5 = 2)", "args": [[15, 20, 35, 40, 50], 30, "nearest-rank", 2], "expect": 20 },
{ "name": "nearest-rank 40th percentile is 20 (rank exactly 2, not 3)", "args": [[15, 20, 35, 40, 50], 40, "nearest-rank", 2], "expect": 20 },
{ "name": "nearest-rank 50th percentile is 35", "args": [[15, 20, 35, 40, 50], 50, "nearest-rank", 2], "expect": 35 },
{ "name": "nearest-rank sorts unsorted input first", "args": [[50, 15, 40, 20, 35], 100, "nearest-rank", 2], "expect": 50 },
{ "name": "nearest-rank 0th percentile is the minimum", "args": [[50, 15, 40, 20, 35], 0, "nearest-rank", 2], "expect": 15 },
{ "name": "nearest-rank 90th of 1..10 is 9", "args": [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 90, "nearest-rank", 0], "expect": 9 },
{ "name": "linear 40th percentile interpolates 60% of the way from 20 to 35", "args": [[15, 20, 35, 40, 50], 40, "linear", 6], "expect": 29 },
{ "name": "linear 75th of 1,2,3,4 matches Excel PERCENTILE.INC(...,0.75) = 3.25", "args": [[4, 3, 2, 1], 75, "linear", 2], "expect": 3.25 },
{ "name": "linear 90th of 1..10 is 9.1", "args": [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 90, "linear", 6], "expect": 9.1 },
{ "name": "linear 0th and 100th are the minimum and maximum", "args": [[-7.5, 3, 12.25], 100, "linear", 2], "expect": 12.25 },
{ "name": "linear 0th is the minimum", "args": [[-7.5, 3, 12.25], 0, "linear", 2], "expect": -7.5 },
{ "name": "a single value is every percentile", "args": [[42], 37.5, "linear", 3], "expect": 42 },
{ "name": "a half rounds away from zero (Python round() would give 0)", "args": [[0, 1], 50, "linear", 0], "expect": 1 },
{ "name": "a negative half rounds away from zero", "args": [[-1, 0], 50, "linear", 0], "expect": -1 },
{ "name": "2.5 rounds up to 3, not to the even 2", "args": [[2, 3], 50, "linear", 0], "expect": 3 },
{ "name": "just under a half rounds down", "args": [[1, 2, 3], 10, "linear", 0], "expect": 1 },
{ "name": "decimals keep the stated places", "args": [[1, 2], 33, "linear", 2], "expect": 1.33 },
{ "name": "an empty sample is an error", "args": [[], 50, "linear", 2], "expectError": "values must not be empty" },
{ "name": "p above 100 is an error", "args": [[1, 2], 101, "linear", 2], "expectError": "p must be between 0 and 100" },
{ "name": "negative p is an error", "args": [[1, 2], -1, "nearest-rank", 2], "expectError": "p must be between 0 and 100" },
{ "name": "an unknown method is an error", "args": [[1, 2], 50, "midpoint", 2], "expectError": "unknown percentile method \"midpoint\"" },
{ "name": "decimals above 12 is an error", "args": [[1, 2], 50, "linear", 13], "expectError": "decimals must be a whole number from 0 to 12" },
{ "name": "a non-number value is an error", "args": [[1, "2"], 50, "linear", 2], "expectError": "values must be finite numbers" }
]