Skip to content

Commit a8e8535

Browse files
authored
Merge pull request #326 from jmid/stddev-precision
Adjust avg and stddev computation and printing
2 parents 7125521 + d7ac098 commit a8e8535

15 files changed

+54
-36
lines changed

.github/workflows/main.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,3 @@ jobs:
3636
- run: opam install . --deps-only --with-test
3737
- run: opam exec -- dune build
3838
- run: opam exec -- dune runtest
39-
if: ${{ matrix.os != 'windows-latest'}}

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
## NEXT RELEASE
44

55
- Restore `Test.make`'s `max_fail` parameter which was accidentally broken in 0.18
6+
- Adjust `stats` computation of average and standard deviation to
7+
limit precision loss, print both using scientific notation, and
8+
workaround MinGW float printing to also pass expect tests
69

710
## 0.24
811

example/QCheck_runner_test.expected.ocaml4.32

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ stats dist:
307307
+++ Stats for stat_display_test_7 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
308308

309309
stats dist:
310-
num: 100000, avg: 336840.90, stddev: 619301756.02, median 895228, min -1073728193, max 1073739280
310+
num: 100000, avg: 336840.90, stddev: 6.193e+8, median 895228, min -1073728193, max 1073739280
311311
-1073728193.. -966354820: ##################################################### 5009
312312
-966354819.. -858981446: #################################################### 5004
313313
-858981445.. -751608072: #################################################### 4917

example/QCheck_runner_test.expected.ocaml4.64

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ stats dist:
307307
+++ Stats for stat_display_test_7 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
308308

309309
stats dist:
310-
num: 100000, avg: 2541076923587387.50, stddev: 2660730801206827008.00, median 158655268318060, min -4611522359435274428, max 4611540922436307689
310+
num: 100000, avg: 2.541e+15, stddev: 2.661e+18, median 158655268318060, min -4611522359435274428, max 4611540922436307689
311311
-4611522359435274428..-4150369195341695293: ##################################################### 4976
312312
-4150369195341695292..-3689216031248116157: ##################################################### 4963
313313
-3689216031248116156..-3228062867154537021: ###################################################### 5038

example/QCheck_runner_test.expected.ocaml5.32

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ stats dist:
307307
+++ Stats for stat_display_test_7 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
308308

309309
stats dist:
310-
num: 100000, avg: -2481754.31, stddev: 618398387.27, median -5669677, min -1073719962, max 1073717275
310+
num: 100000, avg: -2481754.31, stddev: 6.184e+8, median -5669677, min -1073719962, max 1073717275
311311
-1073719962.. -966348101: ##################################################### 4978
312312
-966348100.. -858976239: ##################################################### 5008
313313
-858976238.. -751604377: #################################################### 4907

example/QCheck_runner_test.expected.ocaml5.64

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ stats dist:
307307
+++ Stats for stat_display_test_7 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
308308

309309
stats dist:
310-
num: 100000, avg: -7215552342607541.00, stddev: 2666234426234218496.00, median -16620417636667326, min -4611371852367564818, max 4611613630315464842
310+
num: 100000, avg: -7.216e+15, stddev: 2.666e+18, median -16620417636667326, min -4611371852367564818, max 4611613630315464842
311311
-4611371852367564818..-4150222578233413331: ##################################################### 5003
312312
-4150222578233413330..-3689073304099261843: ####################################################### 5106
313313
-3689073304099261842..-3227924029965110355: ###################################################### 5052

src/core/QCheck2.ml

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,26 +2031,35 @@ module Test = struct
20312031
let stat_max_lines = 20 (* maximum number of lines for a histogram *)
20322032

20332033
let print_stat ((name,_), tbl) =
2034-
let avg = ref 0. in
2034+
let neg_avg_summands = ref [] in
2035+
let pos_avg_summands = ref [] in
20352036
let num = ref 0 in
20362037
let min_idx, max_idx =
20372038
Hashtbl.fold
20382039
(fun i res (m1,m2) ->
2039-
avg := !avg +. float_of_int (i * res);
2040+
let avg_summand = float_of_int (i * res) in
2041+
if avg_summand < 0.
2042+
then neg_avg_summands := avg_summand::!neg_avg_summands
2043+
else pos_avg_summands := avg_summand::!pos_avg_summands;
20402044
num := !num + res;
20412045
min i m1, max i m2)
20422046
tbl (max_int,min_int)
20432047
in
2044-
(* compute average *)
2048+
(* compute average, summing positive/negative separately by order of magnitude *)
2049+
let neg_avg_sums = List.sort Float.compare !neg_avg_summands |> fun xs -> List.fold_right (+.) xs 0. in
2050+
let pos_avg_sums = List.sort Float.compare !pos_avg_summands |> List.fold_left (+.) 0. in
2051+
let avg = ref (neg_avg_sums +. pos_avg_sums) in
20452052
if !num > 0 then (
20462053
avg := !avg /. float_of_int !num
20472054
);
20482055
(* compute std-dev: sqroot of sum of squared distance-to-average
20492056
https://en.wikipedia.org/wiki/Standard_deviation *)
20502057
let stddev =
20512058
Hashtbl.fold
2052-
(fun i res m -> m +. (float_of_int i -. !avg) ** 2. *. float_of_int res)
2053-
tbl 0.
2059+
(fun i res acc -> float_of_int res *. ((float_of_int i -. !avg) ** 2.) :: acc)
2060+
tbl []
2061+
|> List.sort Float.compare (* add summands in increasing order to preserve precision *)
2062+
|> List.fold_left (+.) 0.
20542063
|> (fun s -> if !num>0 then s /. float_of_int !num else s)
20552064
|> sqrt
20562065
in
@@ -2091,10 +2100,17 @@ module Test = struct
20912100
max_val := max !max_val new_count) tbl;
20922101
(* print entries of the table, sorted by increasing index *)
20932102
let out = Buffer.create 128 in
2103+
(* Windows workaround to avoid annoying exponent zero such as "1.859e+018" *)
2104+
let cut_exp_zero s =
2105+
match String.split_on_char '+' s with
2106+
| [signif;exponent] -> Printf.sprintf "%s+%i" signif (int_of_string exponent)
2107+
| _ -> failwith "cut_exp_zero failed to parse scientific notation " ^ s in
2108+
let fmt_float f =
2109+
if f > 1e7 || f < -1e7 then cut_exp_zero (Printf.sprintf "%.3e" f) else Printf.sprintf "%.2f" f in
20942110
Printf.bprintf out "stats %s:\n" name;
20952111
Printf.bprintf out
2096-
" num: %d, avg: %.2f, stddev: %.2f, median %d, min %d, max %d\n"
2097-
!num !avg stddev !median min_idx max_idx;
2112+
" num: %d, avg: %s, stddev: %s, median %d, min %d, max %d\n"
2113+
!num (fmt_float !avg) (fmt_float stddev) !median min_idx max_idx;
20982114
let indwidth =
20992115
let str_width i = String.length (Printf.sprintf "%d" i) in
21002116
List.map str_width [min_idx; max_idx; min_idx + bucket_size * hist_size] |> List.fold_left max min_int in

test/core/QCheck2_expect_test.expected.ocaml4.32

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,7 +1434,7 @@ stats dist:
14341434
+++ Stats for int dist ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
14351435

14361436
stats dist:
1437-
num: 100000, avg: -298652.90, stddev: 619096154.85, median 419404, min -1073741519, max 1073728237
1437+
num: 100000, avg: -298652.90, stddev: 6.191e+8, median 419404, min -1073741519, max 1073728237
14381438
-1073741519.. -966368032: ##################################################### 4984
14391439
-966368031.. -858994544: ###################################################### 5025
14401440
-858994543.. -751621056: ###################################################### 5035
@@ -1459,7 +1459,7 @@ stats dist:
14591459
+++ Stats for oneof int dist ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
14601460

14611461
stats dist:
1462-
num: 1000, avg: 1073741.63, stddev: 676575790.92, median 0, min -1073741824, max 1073741823
1462+
num: 1000, avg: 1073741.63, stddev: 6.766e+8, median 0, min -1073741824, max 1073741823
14631463
-1073741824.. -966367642: ################## 208
14641464
-966367641.. -858993459: 0
14651465
-858993458.. -751619276: 0
@@ -1688,7 +1688,7 @@ random seed: 153870556
16881688
+++ Stats for int_dist_empty_bucket ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16891689

16901690
stats dist:
1691-
num: 1000, avg: 2229293.51, stddev: 427568354.78, median 9, min -1072726813, max 1073741823
1691+
num: 1000, avg: 2229293.51, stddev: 4.276e+8, median 9, min -1072726813, max 1073741823
16921692
-1072726813.. -965403382: ## 22
16931693
-965403381.. -858079950: ## 28
16941694
-858079949.. -750756518: # 17

test/core/QCheck2_expect_test.expected.ocaml4.64

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,7 +1496,7 @@ stats dist:
14961496
+++ Stats for int dist ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
14971497

14981498
stats dist:
1499-
num: 100000, avg: 6739840024355437.00, stddev: 2654793546877646336.00, median 2435838602111153, min -4611682300221562449, max 4611492907363159042
1499+
num: 100000, avg: 6.740e+15, stddev: 2.655e+18, median 2435838602111153, min -4611682300221562449, max 4611492907363159042
15001500
-4611682300221562449..-4150523539842326354: #################################################### 4927
15011501
-4150523539842326353..-3689364779463090258: #################################################### 4923
15021502
-3689364779463090257..-3228206019083854162: #################################################### 4923
@@ -1521,7 +1521,7 @@ stats dist:
15211521
+++ Stats for oneof int dist ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
15221522

15231523
stats dist:
1524-
num: 1000, avg: 4611686018427388.00, stddev: 2905870896563567616.00, median 0, min -4611686018427387904, max 4611686018427387903
1524+
num: 1000, avg: 4.612e+15, stddev: 2.906e+18, median 0, min -4611686018427387904, max 4611686018427387903
15251525
-4611686018427387904..-4150517416584649089: ################## 208
15261526
-4150517416584649088..-3689348814741910273: 0
15271527
-3689348814741910272..-3228180212899171457: 0
@@ -1750,7 +1750,7 @@ random seed: 153870556
17501750
+++ Stats for int_dist_empty_bucket ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
17511751

17521752
stats dist:
1753-
num: 1000, avg: 48985084121559400.00, stddev: 1793541561270566400.00, median 9, min -4580864984167113344, max 4611686018427387903
1753+
num: 1000, avg: 4.899e+16, stddev: 1.794e+18, median 9, min -4580864984167113344, max 4611686018427387903
17541754
-4580864984167113344..-4121237434037388289: ## 23
17551755
-4121237434037388288..-3661609883907663233: # 19
17561756
-3661609883907663232..-3201982333777938177: ## 28

test/core/QCheck2_expect_test.expected.ocaml5.32

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,7 +1417,7 @@ stats dist:
14171417
+++ Stats for int dist ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
14181418

14191419
stats dist:
1420-
num: 100000, avg: 1375300.54, stddev: 620110315.04, median -3852464, min -1073736753, max 1073733862
1420+
num: 100000, avg: 1375300.54, stddev: 6.201e+8, median -3852464, min -1073736753, max 1073733862
14211421
-1073736753.. -966363223: #################################################### 4972
14221422
-966363222.. -858989692: ##################################################### 5032
14231423
-858989691.. -751616161: #################################################### 4928
@@ -1442,7 +1442,7 @@ stats dist:
14421442
+++ Stats for oneof int dist ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
14431443

14441444
stats dist:
1445-
num: 1000, avg: 1073741.60, stddev: 673131652.31, median 0, min -1073741824, max 1073741823
1445+
num: 1000, avg: 1073741.60, stddev: 6.731e+8, median 0, min -1073741824, max 1073741823
14461446
-1073741824.. -966367642: ################# 198
14471447
-966367641.. -858993459: 0
14481448
-858993458.. -751619276: 0
@@ -1672,7 +1672,7 @@ random seed: 153870556
16721672
+++ Stats for int_dist_empty_bucket ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16731673

16741674
stats dist:
1675-
num: 1000, avg: 12189159.05, stddev: 451294853.72, median 10, min -1073230792, max 1073741823
1675+
num: 1000, avg: 1.219e+7, stddev: 4.513e+8, median 10, min -1073230792, max 1073741823
16761676
-1073230792.. -965882162: ## 19
16771677
-965882161.. -858533531: ### 30
16781678
-858533530.. -751184900: ### 29

0 commit comments

Comments
 (0)