ulpwise 0.3.1__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {ulpwise-0.3.1 → ulpwise-0.3.2}/CHANGELOG.md +23 -0
  2. {ulpwise-0.3.1 → ulpwise-0.3.2}/Cargo.lock +1 -1
  3. {ulpwise-0.3.1 → ulpwise-0.3.2}/Cargo.toml +1 -1
  4. {ulpwise-0.3.1 → ulpwise-0.3.2}/PKG-INFO +18 -1
  5. {ulpwise-0.3.1 → ulpwise-0.3.2}/README.md +17 -0
  6. {ulpwise-0.3.1 → ulpwise-0.3.2}/pyproject.toml +1 -1
  7. {ulpwise-0.3.1 → ulpwise-0.3.2}/python/ulpwise/__init__.py +1 -1
  8. {ulpwise-0.3.1 → ulpwise-0.3.2}/python/ulpwise/corpus/cases.json +85 -1
  9. {ulpwise-0.3.1 → ulpwise-0.3.2}/python/ulpwise/survey.py +3 -1
  10. ulpwise-0.3.2/studies/accuracy-survey-2026-10-half/README.md +133 -0
  11. ulpwise-0.3.2/studies/accuracy-survey-2026-10-half/results.csv +91 -0
  12. ulpwise-0.3.2/studies/accuracy-survey-2026-10-half/results.md +105 -0
  13. {ulpwise-0.3.1 → ulpwise-0.3.2}/tests/test_survey.py +3 -0
  14. {ulpwise-0.3.1 → ulpwise-0.3.2}/.github/dependabot.yml +0 -0
  15. {ulpwise-0.3.1 → ulpwise-0.3.2}/.github/workflows/ci.yml +0 -0
  16. {ulpwise-0.3.1 → ulpwise-0.3.2}/.github/workflows/release.yml +0 -0
  17. {ulpwise-0.3.1 → ulpwise-0.3.2}/.gitignore +0 -0
  18. {ulpwise-0.3.1 → ulpwise-0.3.2}/CONTRIBUTING.md +0 -0
  19. {ulpwise-0.3.1 → ulpwise-0.3.2}/LICENSE-APACHE +0 -0
  20. {ulpwise-0.3.1 → ulpwise-0.3.2}/LICENSE-MIT +0 -0
  21. {ulpwise-0.3.1 → ulpwise-0.3.2}/examples/sqrt_knife_values.py +0 -0
  22. {ulpwise-0.3.1 → ulpwise-0.3.2}/examples/torch_sqrt_conformance.py +0 -0
  23. {ulpwise-0.3.1 → ulpwise-0.3.2}/python/ulpwise/__main__.py +0 -0
  24. {ulpwise-0.3.1 → ulpwise-0.3.2}/python/ulpwise/corpus/__init__.py +0 -0
  25. {ulpwise-0.3.1 → ulpwise-0.3.2}/python/ulpwise/plugin.py +0 -0
  26. {ulpwise-0.3.1 → ulpwise-0.3.2}/python/ulpwise/scan.py +0 -0
  27. {ulpwise-0.3.1 → ulpwise-0.3.2}/src/edge.rs +0 -0
  28. {ulpwise-0.3.1 → ulpwise-0.3.2}/src/exact.rs +0 -0
  29. {ulpwise-0.3.1 → ulpwise-0.3.2}/src/knife.rs +0 -0
  30. {ulpwise-0.3.1 → ulpwise-0.3.2}/src/lib.rs +0 -0
  31. {ulpwise-0.3.1 → ulpwise-0.3.2}/src/py.rs +0 -0
  32. {ulpwise-0.3.1 → ulpwise-0.3.2}/src/ulp.rs +0 -0
  33. {ulpwise-0.3.1 → ulpwise-0.3.2}/studies/accuracy-survey-2026-09/README.md +0 -0
  34. {ulpwise-0.3.1 → ulpwise-0.3.2}/studies/accuracy-survey-2026-09/results.csv +0 -0
  35. {ulpwise-0.3.1 → ulpwise-0.3.2}/studies/accuracy-survey-2026-09/results.md +0 -0
  36. {ulpwise-0.3.1 → ulpwise-0.3.2}/tests/test_core.py +0 -0
  37. {ulpwise-0.3.1 → ulpwise-0.3.2}/tests/test_corpus.py +0 -0
  38. {ulpwise-0.3.1 → ulpwise-0.3.2}/tests/test_scan.py +0 -0
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.2 (2026-10-06)
4
+
5
+ - Two regression corpus cases for pytorch #199850: `torch.erf` in bfloat16 and float16 on CPU returns 0 at and
6
+ below 1.8e-7 and loses relative accuracy below 1e-3 (13404 bfloat16 ulps, 5 float16 ulps at worst), found with
7
+ the half precision rows of `ulpwise survey --functions erf --backends torch --dtypes f16,bf16`.
8
+ - Two regression corpus cases for pytorch #199867: `torch.special.logit` in float16 and bfloat16 on CPU rounds `1 - x`
9
+ and `x / (1 - x)` to the input dtype before the log, so logit(0.499756) in float16 is -0.000488 for an exact -0.000977
10
+ (512 ulp, 64 bfloat16 ulp at worst), found with `ulpwise survey --functions logit --backends torch --dtypes f16,bf16`.
11
+ - `studies/accuracy-survey-2026-10-half`: the second accuracy survey, torch 2.14.0+cpu in float16 and bfloat16 for the
12
+ 45 functions with half precision CPU kernels. 33 float16 and 34 bfloat16 rows of 45 are correctly rounded; `erf`
13
+ (pytorch #199850) and `logit` (pytorch #199867) lose their digits before the rounding step, `polygamma(2, x)` in
14
+ float16 is off at every half integer in `(-1024, -256)` because the Hurwitz zeta sum accumulates in float for the
15
+ reduced types, and the activation tails and the `rsqrt` and `i0e` vector versus scalar disagreements of September
16
+ show again.
17
+ - `ulpwise survey`: the `polygamma_1` and `polygamma_2` references at a non positive integer are now the signed
18
+ infinity of the pole, `+inf` for an odd order (the limit from both sides) and `-inf` for an even one (the sign of
19
+ `(-1) ** (n + 1) * n! * zeta(n + 1, x)`, which is what scipy, torch and jax return), instead of a domain error
20
+ that expected `nan`. The f16 and bf16 grids reach the integers from 2048 and 256 up, so every negative point
21
+ past there was a pole and counted as a nonfinite mismatch: on torch 2.14 the two functions had 354 of 3546
22
+ float16 points and 492 of 4016 bfloat16 points each, `polygamma_2` has 0 now in every dtype and `polygamma_1`
23
+ keeps 491 bfloat16, 4 float32 and 2 float16 points where torch returns a large finite value instead of `inf`
24
+ at a negative integer (pytorch #198663).
25
+
3
26
  ## 0.3.1 (2026-10-05)
4
27
 
5
28
  - `ulpwise survey` takes `f16` and `bf16` in `--dtypes` (the default stays `f32,f64`): torch and jax get half
@@ -120,7 +120,7 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
120
120
 
121
121
  [[package]]
122
122
  name = "ulpwise"
123
- version = "0.3.1"
123
+ version = "0.3.2"
124
124
  dependencies = [
125
125
  "pyo3",
126
126
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "ulpwise"
3
- version = "0.3.1"
3
+ version = "0.3.2"
4
4
  edition = "2021"
5
5
  rust-version = "1.86"
6
6
  license = "MIT OR Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ulpwise
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Framework :: Pytest
6
6
  Classifier: Intended Audience :: Developers
@@ -226,6 +226,8 @@ PYTHONPATH=/tmp/kornia-0.8.3 ulpwise corpus --repo kornia # 31 present, 0 fi
226
226
  | torchvision #9676 `clamp_bounding_boxes` collapses slightly tilted rotated boxes to a point | geometry | open |
227
227
  | pytorch #198663 `polygamma(1, x)` float64 keeps 9 digits (series stops at `1/42`), float32 loses all for large negative `x` | truncation, rounding | open |
228
228
  | pytorch #198664 `erfcx` off by `x*x/2` ulps for negative `x` (`exp` at the rounded square) | rounding | open |
229
+ | pytorch #199850 `torch.erf` in bfloat16 and float16 on CPU returns 0 at and below 1.8e-7 and loses relative accuracy below 1e-3 (13404 bfloat16 ulps, 5 float16 ulps) | cancellation | open |
230
+ | pytorch #199867 `torch.special.logit` in float16 and bfloat16 on CPU rounds `1 - x` and `x / (1 - x)` to the input dtype before the log, logit(0.499756) is -0.000488 for -0.000977 (512 float16 ulps, 64 bfloat16 ulps) | rounding | open |
229
231
 
230
232
  Cases marked `open` have an issue with the complete patch attached and no merged fix yet. Every case
231
233
  is an expected failure until the installed release contains the fix (`fixed_in_release` in
@@ -341,6 +343,21 @@ logged and skipped.
341
343
  - scipy's float64 `lgamma` does not handle the zeros at 1 and 2, and its Bessel functions lose the
342
344
  phase at large `x`.
343
345
 
346
+ [`studies/accuracy-survey-2026-10-half`](https://github.com/Nicholas022400701/ulpwise/blob/main/studies/accuracy-survey-2026-10-half/README.md)
347
+ is the second run, the 45 functions with torch float16 and bfloat16 CPU kernels measured in the ulps of
348
+ those dtypes on the same build. 33 of the 45 float16 rows and 34 of the bfloat16 rows are correctly
349
+ rounded over the whole grid; the exceptions:
350
+
351
+ - `erf` goes through a formula with 1.5e-7 absolute error, 254 bfloat16 ulps and `-0` below
352
+ `|x| = 1.8e-7` (pytorch #199850).
353
+ - `logit` rounds `1 - x` and `x / (1 - x)` to the input dtype before the log, 512 float16 ulps at
354
+ `x = 0.499756` while the CUDA kernel computes in float (pytorch #199867).
355
+ - `polygamma(2, x)` in float16 is off at every half integer in `(-1024, -256)`, 1,540 ulps at
356
+ `x = -1023.5`, because the Hurwitz zeta sum accumulates in float for the reduced types and in
357
+ double for float32.
358
+ - the `gelu`, `gelu_tanh`, `silu` and `sigmoid` tails and the `rsqrt` and `i0e` vector versus scalar
359
+ disagreements are the float32 findings of September seen through coarser ulps.
360
+
344
361
  ## How the exact oracle works
345
362
 
346
363
  For `sqrt(x)` the candidate `r` and the midpoint `m` between `r` and its neighbour are written as
@@ -197,6 +197,8 @@ PYTHONPATH=/tmp/kornia-0.8.3 ulpwise corpus --repo kornia # 31 present, 0 fi
197
197
  | torchvision #9676 `clamp_bounding_boxes` collapses slightly tilted rotated boxes to a point | geometry | open |
198
198
  | pytorch #198663 `polygamma(1, x)` float64 keeps 9 digits (series stops at `1/42`), float32 loses all for large negative `x` | truncation, rounding | open |
199
199
  | pytorch #198664 `erfcx` off by `x*x/2` ulps for negative `x` (`exp` at the rounded square) | rounding | open |
200
+ | pytorch #199850 `torch.erf` in bfloat16 and float16 on CPU returns 0 at and below 1.8e-7 and loses relative accuracy below 1e-3 (13404 bfloat16 ulps, 5 float16 ulps) | cancellation | open |
201
+ | pytorch #199867 `torch.special.logit` in float16 and bfloat16 on CPU rounds `1 - x` and `x / (1 - x)` to the input dtype before the log, logit(0.499756) is -0.000488 for -0.000977 (512 float16 ulps, 64 bfloat16 ulps) | rounding | open |
200
202
 
201
203
  Cases marked `open` have an issue with the complete patch attached and no merged fix yet. Every case
202
204
  is an expected failure until the installed release contains the fix (`fixed_in_release` in
@@ -312,6 +314,21 @@ logged and skipped.
312
314
  - scipy's float64 `lgamma` does not handle the zeros at 1 and 2, and its Bessel functions lose the
313
315
  phase at large `x`.
314
316
 
317
+ [`studies/accuracy-survey-2026-10-half`](https://github.com/Nicholas022400701/ulpwise/blob/main/studies/accuracy-survey-2026-10-half/README.md)
318
+ is the second run, the 45 functions with torch float16 and bfloat16 CPU kernels measured in the ulps of
319
+ those dtypes on the same build. 33 of the 45 float16 rows and 34 of the bfloat16 rows are correctly
320
+ rounded over the whole grid; the exceptions:
321
+
322
+ - `erf` goes through a formula with 1.5e-7 absolute error, 254 bfloat16 ulps and `-0` below
323
+ `|x| = 1.8e-7` (pytorch #199850).
324
+ - `logit` rounds `1 - x` and `x / (1 - x)` to the input dtype before the log, 512 float16 ulps at
325
+ `x = 0.499756` while the CUDA kernel computes in float (pytorch #199867).
326
+ - `polygamma(2, x)` in float16 is off at every half integer in `(-1024, -256)`, 1,540 ulps at
327
+ `x = -1023.5`, because the Hurwitz zeta sum accumulates in float for the reduced types and in
328
+ double for float32.
329
+ - the `gelu`, `gelu_tanh`, `silu` and `sigmoid` tails and the `rsqrt` and `i0e` vector versus scalar
330
+ disagreements are the float32 findings of September seen through coarser ulps.
331
+
315
332
  ## How the exact oracle works
316
333
 
317
334
  For `sqrt(x)` the candidate `r` and the midpoint `m` between `r` and its neighbour are written as
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "ulpwise"
7
- version = "0.3.1"
7
+ version = "0.3.2"
8
8
  description = "Numerical conformance testing for ML code: float edge values, exact rounding oracles, knife-edge finders and a pytest plugin"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT OR Apache-2.0" }
@@ -30,7 +30,7 @@ from ._core import special as _special_core
30
30
  from ._core import ulp_distance as _ulp_distance_core
31
31
  from ._core import ulp_distances as _ulp_distances_core
32
32
 
33
- __version__ = "0.3.1"
33
+ __version__ = "0.3.2"
34
34
 
35
35
  __all__ = [
36
36
  "UNARY_OPS",
@@ -1019,6 +1019,90 @@
1019
1019
  "rtol": 0.0
1020
1020
  },
1021
1021
  "before_fix": "[1] on ultralytics 8.4.163: nc = 1 and no labels, \"ignoring corrupt image/label: non-normalized or out of bounds coordinates [1.15 1.15 ...]\""
1022
+ },
1023
+ {
1024
+ "id": "pytorch-199850-erf-bfloat16-small-arguments",
1025
+ "repo": "pytorch/pytorch",
1026
+ "pr": null,
1027
+ "issue": 199850,
1028
+ "merged_at": null,
1029
+ "kind": "cancellation",
1030
+ "title": "torch.erf in bfloat16 on CPU returns 0 for |x| <= 1.8e-7 and loses relative accuracy below 1e-3",
1031
+ "symptom": "bfloat16 and float16 erf go through Vectorized<float>::erf(), the Abramowitz and Stegun 7.1.26 formula 1 - r * t * exp(-x * x), whose absolute error is 1.5e-7; below |x| = 1e-3 that error is a visible fraction of erf(x) ~ 1.128 x and below 1.5e-7 the 1 - 1 rounds to exactly 0. Of the 16128 bfloat16 inputs in (0, 0.5], 14102 are more than 1 ulp off, 13379 return 0, the worst is 13404 ulp. The MKL float32 and float64 paths are correct; float32 without MKL and under torch.compile takes the same code (issue #198183). The patch adds a Taylor series branch for |x| < 0.5 (Draft PR #199851).",
1032
+ "requires": [
1033
+ "torch"
1034
+ ],
1035
+ "fixed_in_release": null,
1036
+ "repro": "import torch\nxs = torch.tensor([1e-7, 5e-7, 1e-6, 1e-5], dtype=torch.bfloat16)\nactual = torch.erf(xs).tolist()\n# erf at the bfloat16 inputs in float64, rounded to bfloat16\nexpected = [1.1315569281578064e-07, 5.62518835067749e-07, 1.125037670135498e-06, 1.1324882507324219e-05]\n",
1037
+ "check": {
1038
+ "type": "max_ulp",
1039
+ "dtype": "bf16",
1040
+ "max_ulp": 1
1041
+ },
1042
+ "before_fix": "[0.0, 4.172325134277344e-07, 1.1920928955078125e-06, 1.1563301086425781e-05] on torch 2.14.0 (13299, 55, 9 and 4 ulp)"
1043
+ },
1044
+ {
1045
+ "id": "pytorch-199850-erf-float16-small-arguments",
1046
+ "repo": "pytorch/pytorch",
1047
+ "pr": null,
1048
+ "issue": 199850,
1049
+ "merged_at": null,
1050
+ "kind": "cancellation",
1051
+ "title": "torch.erf in float16 on CPU returns 0 for |x| <= 1.8e-7 and is up to 5 ulp off below 1e-3",
1052
+ "symptom": "Same Vectorized<float>::erf() path as the bfloat16 case; float16 has three more bits, so the 1.5e-7 absolute error shows as 1240 of the 14336 inputs in (0, 0.5] more than 1 ulp off, at most 5 ulp, and the three inputs at or below 1.8e-7 return 0.",
1053
+ "requires": [
1054
+ "torch"
1055
+ ],
1056
+ "fixed_in_release": null,
1057
+ "repro": "import torch\nxs = torch.tensor([1e-7, 5e-7, 1e-6, 1e-5], dtype=torch.float16)\nactual = torch.erf(xs).tolist()\n# erf at the float16 inputs in float64, rounded to float16\nexpected = [1.1920928955078125e-07, 5.364418029785156e-07, 1.1324882507324219e-06, 1.1324882507324219e-05]\n",
1058
+ "check": {
1059
+ "type": "max_ulp",
1060
+ "dtype": "f16",
1061
+ "max_ulp": 1
1062
+ },
1063
+ "before_fix": "[0.0, 4.172325134277344e-07, 1.1920928955078125e-06, 1.1563301086425781e-05] on torch 2.14.0 (2, 2, 1 and 4 ulp)"
1064
+ },
1065
+ {
1066
+ "id": "pytorch-199867-logit-bfloat16-intermediate-rounding",
1067
+ "repo": "pytorch/pytorch",
1068
+ "pr": null,
1069
+ "issue": 199867,
1070
+ "merged_at": null,
1071
+ "kind": "rounding",
1072
+ "title": "torch.special.logit in bfloat16 on CPU rounds 1 - x and x / (1 - x) to bfloat16 before the log, 64 ulp at x = 0.498047",
1073
+ "symptom": "The CPU kernel computes 1 - x and x / (1 - x) in the input dtype and only the log in float, so near x = 0.5, where logit is small, the two roundings take most of the digits: logit(0.499756) in float16 is -0.000488 for an exact -0.000977 (512 ulp), 582 of the 15358 float16 values in (0, 1) are more than 1 ulp off and 59 of the 16254 bfloat16 values, 64 ulp at worst. The CUDA kernel computes in float. The patch computes in float and rounds once, as sigmoid_kernel does for the reduced types.",
1074
+ "requires": [
1075
+ "torch"
1076
+ ],
1077
+ "fixed_in_release": null,
1078
+ "repro": "import torch\nxs = torch.tensor([0.498046875, 0.490234375, 0.470703125, 0.51953125], dtype=torch.bfloat16)\nactual = torch.special.logit(xs).tolist()\n# logit at the bfloat16 inputs in float64, rounded to bfloat16\nexpected = [-0.0078125, -0.0390625, -0.1171875, 0.078125]\n",
1079
+ "check": {
1080
+ "type": "max_ulp",
1081
+ "dtype": "bf16",
1082
+ "max_ulp": 1
1083
+ },
1084
+ "before_fix": "[-0.00390625, -0.035888671875, -0.1201171875, 0.0751953125] on torch 2.14.0 (64, 13, 5.7 and 6.1 ulp)"
1085
+ },
1086
+ {
1087
+ "id": "pytorch-199867-logit-float16-intermediate-rounding",
1088
+ "repo": "pytorch/pytorch",
1089
+ "pr": null,
1090
+ "issue": 199867,
1091
+ "merged_at": null,
1092
+ "kind": "rounding",
1093
+ "title": "torch.special.logit in float16 on CPU rounds 1 - x and x / (1 - x) to float16 before the log, 512 ulp at x = 0.499756",
1094
+ "symptom": "The CPU kernel computes 1 - x and x / (1 - x) in the input dtype and only the log in float, so near x = 0.5, where logit is small, the two roundings take most of the digits: logit(0.499756) in float16 is -0.000488 for an exact -0.000977 (512 ulp), 582 of the 15358 float16 values in (0, 1) are more than 1 ulp off and 59 of the 16254 bfloat16 values, 64 ulp at worst. The CUDA kernel computes in float. The patch computes in float and rounds once, as sigmoid_kernel does for the reduced types.",
1095
+ "requires": [
1096
+ "torch"
1097
+ ],
1098
+ "fixed_in_release": null,
1099
+ "repro": "import torch\nxs = torch.tensor([0.499755859375, 0.497314453125, 0.489990234375, 0.52001953125], dtype=torch.float16)\nactual = torch.special.logit(xs).tolist()\n# logit at the float16 inputs in float64, rounded to float16\nexpected = [-0.0009765625, -0.0107421875, -0.0400390625, 0.08013916015625]\n",
1100
+ "check": {
1101
+ "type": "max_ulp",
1102
+ "dtype": "f16",
1103
+ "max_ulp": 1
1104
+ },
1105
+ "before_fix": "[-0.00048828125, -0.01129150390625, -0.039337158203125, 0.0797119140625] on torch 2.14.0 (512, 72, 23 and 6.7 ulp)"
1022
1106
  }
1023
1107
  ]
1024
- }
1108
+ }
@@ -230,7 +230,9 @@ def _ref_polygamma(n):
230
230
  def f(x):
231
231
  mp = _mp()
232
232
  if x <= 0 and x == mp.floor(x):
233
- return None
233
+ # the pole: +inf from both sides for an odd n; for an even n the two sides disagree and the reference
234
+ # is the sign of (-1) ** (n + 1) * n! * zeta(n + 1, x), which is what scipy, torch and jax return
235
+ return mp.mpf("inf") if n % 2 else mp.mpf("-inf")
234
236
  return mp.polygamma(n, x)
235
237
 
236
238
  return f
@@ -0,0 +1,133 @@
1
+ # Accuracy survey, October 2026: torch in float16 and bfloat16
2
+
3
+ The 45 functions of the September survey for which torch has a float16 and a bfloat16 CPU kernel,
4
+ measured in the ulps of those dtypes, on the same machine and the same torch build. The question
5
+ this time: a half precision kernel in torch is supposed to compute in float and round once, so the
6
+ rows should all read 0.5. Which ones do not, and why.
7
+
8
+ | | |
9
+ |---|---|
10
+ | command | `ulpwise survey --backends torch --dtypes f16,bf16 --out studies/accuracy-survey-2026-10-half` on ulpwise `main` at 0b12fb8 (0.3.1 plus the `polygamma` pole references below) |
11
+ | backends | torch 2.14.0+cpu (CPU capability AVX512, MKL available) |
12
+ | reference | mpmath at 200 bits, evaluated at the float16 or bfloat16 input the kernel actually saw |
13
+ | inputs | 600 log spaced points over each function's domain, clipped to the finite range of the dtype, plus the named edge values of the dtype, 480 to 662 inputs per row, subnormals included |
14
+ | platform | Linux x86_64, Python 3.13, mpmath 1.3.0 |
15
+ | files | `results.csv` (one row per function and dtype with every metric and the worst input), `results.md` (the pivot table) |
16
+
17
+ The 16 functions without half precision kernels in torch (`bessel_*`, `modified_bessel_*`,
18
+ `scaled_modified_bessel_*`, `spherical_bessel_j0`, `airy_ai`, `erfcx`, `log_ndtr`, `ndtri`, `zeta`)
19
+ are logged and skipped, so there are 90 rows.
20
+
21
+ ## How to read a number
22
+
23
+ The same metric as in September: `|got - exact| / spacing(dtype, exact)`, correct rounding is 0.5,
24
+ and an exact result of zero or in the subnormal range produces enormous numbers that are not
25
+ precision bugs. Three things are specific to the half precision grids:
26
+
27
+ 1. **bfloat16 has 8 significant bits and float16 11.** Every bfloat16 value with `|x| >= 256` is
28
+ an integer, every float16 value with `|x| >= 2048` is one. A log spaced grid over a domain that
29
+ reaches 1e5 therefore spends a quarter of its points on integers, which is why `sinc` in
30
+ bfloat16 reads `8.4e32` (the exact value at an integer is 0) and why `polygamma_1` in bfloat16
31
+ has 75 non finite mismatches (every negative point past 256 is a pole).
32
+ 2. **The float16 range is narrow.** Normal numbers stop at 6.1e-5, the smallest subnormal is 6e-8
33
+ and the largest value is 65504. A tail value such as `gelu(-5.57) = -7.1e-8` is a subnormal with
34
+ one significant bit; its ulp is 6e-8 and torch's `-0` there counts as 1.19 ulps, not as the
35
+ millions the same formula gives in float32.
36
+ 3. **The two tolerance columns** use `torch.testing`'s defaults for the dtype, `rtol = 1e-3,
37
+ atol = 1e-5` for float16 and `rtol = 1.6e-2, atol = 1e-5` for bfloat16, and the per op override
38
+ from `op_db`. One ulp of float16 is between 4.9e-4 and 9.8e-4 relative, so the default float16
39
+ tolerance is about one ulp and the bfloat16 one about four.
40
+
41
+ The `polygamma` reference changed since September: at a non positive integer it is now the signed
42
+ infinity of the pole (`+inf` for `polygamma_1`, `-inf` for `polygamma_2`, the sign torch, scipy and
43
+ jax return) instead of a domain error that expected `nan`, so a kernel that returns the infinity at
44
+ a pole is no longer counted as a mismatch. The September `polygamma_1` float32 row counts 7 non
45
+ finite mismatches with the old reference and would count 4 with this one (the changelog entry on
46
+ the `polygamma` references has the per dtype numbers); the measured errors do not depend on the
47
+ reference at the poles, and the September files are left as they were measured.
48
+
49
+ ## Findings
50
+
51
+ ### Two kernels lose their digits before the rounding step
52
+
53
+ In both cases the half precision path is not "compute in float and round once", and the errors
54
+ are far outside what the dtype can represent.
55
+
56
+ - **`erf` in bfloat16 and float16** (pytorch #199850, patch and Draft PR #199851). 254 ulps in
57
+ bfloat16 at `x = -1.3e-8` (torch returns `-0`), p99 241, 34.6 percent of the grid beyond 1 ulp;
58
+ 4.55 ulps in float16, 24.5 percent beyond 1 ulp. The reduced types go through
59
+ `Vectorized<float>::erf()`, the Abramowitz and Stegun 7.1.26 formula `1 - r * t * exp(-x * x)`,
60
+ whose absolute error of 1.5e-7 is invisible for a float32 result of order 1 but is the whole
61
+ result when `erf(x) ~ 1.128 x` is small: below `|x| = 1.8e-7` the `1 - 1` rounds to exactly 0.
62
+ Over every bfloat16 value in `(0, 0.5]`, 14,102 of 16,128 inputs are more than 1 ulp off and
63
+ 13,379 return 0; float32 and float64 are correct on this build because they take the MKL path.
64
+ - **`logit` in float16 and bfloat16** (pytorch #199867, patch on a branch). 72 ulps in float16 at
65
+ `x = 0.49731`, 29 of the 575 inputs fail the default float16 tolerance; 64 ulps in bfloat16, 10
66
+ of 480. The CPU kernel computes `1 - x` and `x / (1 - x)` in the input dtype and only the `log`
67
+ in float, so near `x = 0.5`, where the result is small, the two roundings take most of its
68
+ digits: `logit(0.499756)` in float16 is `-0.000488` for an exact `-0.000977`, 512 ulps, and 582 of
69
+ the 15,358 float16 values in `(0, 1)` are beyond 1 ulp (59 of 16,254 in bfloat16). Computing in
70
+ float and rounding once is correctly rounded at every one of those inputs, and that is what the
71
+ CUDA kernel already does. The `OpInfo` reference test carries
72
+ `precisionOverride({torch.bfloat16: 5e-1, torch.float16: 5e-1})`, an absolute tolerance of 0.5
73
+ on values below 0.01, so the `op fail` column is 0 for both rows.
74
+
75
+ ### `polygamma(2, x)` in float16 at the negative half integers
76
+
77
+ 14 ulps on the grid at `x = -578.5` (got `-2.146e-6`, exact `-2.983e-6`, a 28 percent error). Off
78
+ the grid it is worse: at every one of the 768 float16 half integers in `(-1024, -256)` the result is
79
+ more than 1 ulp off, 1,540 ulps at `x = -1023.5` (got `-2.38e-7`, exact `-9.54e-7`), and so are 203
80
+ of the 255 half integers in `(-256, -1)`. float32 is within 1e-4 float16 ulps at the same inputs.
81
+ These are the points where the function is small: at a half integer the reflection term of
82
+ `polygamma(2, x)` vanishes and the value is `polygamma(2, 1 - x) ~ -1 / x^2`, while the Hurwitz
83
+ zeta sum behind it adds terms of order 1 that cancel. torch's `calc_polygamma<Half>` accumulates
84
+ that sum in `float` (`acc_type<Half, false>`) and `calc_polygamma<float>` in `double`, which is why
85
+ float32 keeps its digits and float16 keeps an absolute error of about 1e-6. bfloat16 does not show
86
+ it only because bfloat16 has no half integers past 256 and the values below 256 are of order 1. Not
87
+ reported upstream yet (the fix would compute the reduced types through the float path, as
88
+ `calc_digamma` does). On CUDA `acc_type<float, true>` is `float`, so by the same reading of the
89
+ source the float32 kernel there has the same problem; not measured.
90
+
91
+ ### The formula tails, as in September
92
+
93
+ - **`gelu` and `gelu_tanh` in bfloat16** return `-0` from about `x = -5.5` down, where
94
+ `1 + erf(x / sqrt 2)` and `1 + tanh(t)` are exactly 0 in float: 242 and 250 ulps at the worst grid
95
+ point, 2.1 and 1.6 percent of the grid beyond 10 ulps. bfloat16 has the float32 exponent range, so
96
+ `gelu(-7.875) = -1.3e-14` is an ordinary normal number there. In float16 the same inputs are
97
+ below the subnormal range and the row reads 1.19 ulps (see above).
98
+ - **`silu(-92.5)` and `sigmoid(-92.5)` in bfloat16** return `-0` and 0 because `exp(92.5)` overflows
99
+ float32: 67.7 and 0.73 ulps, exactly the float32 behaviour of September measured in coarser ulps.
100
+
101
+ ### The vectorized kernel and the scalar tail disagree
102
+
103
+ `rsqrt` (128 of 571 float16 inputs, 184 of 615 bfloat16) and `i0e` (303 of 588, 413 of 620) return
104
+ different bits for the same input depending on whether it landed in the vector body or in the
105
+ scalar tail of the tensor; `gelu` in float16 differs at 3 inputs. Both paths are within 1.5 ulps
106
+ (`rsqrt` 0.95 and 1.08, `i0e` 1.46 and 0.65), so this is determinism and not precision: the result
107
+ of an element depends on the tensor size and alignment.
108
+
109
+ ### Small things
110
+
111
+ - `entr` reads 1.19 ulps in float16 (`x = 3088`) and 1.2 in bfloat16: `-x * log(x)` with the log
112
+ rounded to the dtype before the product.
113
+ - `polygamma_1` in bfloat16 returns a large finite number instead of `inf` at the 75 negative
114
+ integers of its grid (`4.3e9` at `-300`), the float32 reflection `pi^2 / sin(pi x)^2` with a
115
+ rounded argument. float16 returns `inf` at the same points because `4.3e9` overflows float16.
116
+ - The single non finite mismatch of `reciprocal` and of `digamma` in each dtype is the edge value
117
+ `-0.0`, where torch returns an infinity and the reference has no value.
118
+
119
+ ### Everything else rounds correctly
120
+
121
+ 33 of the 45 float16 rows and 34 of the 45 bfloat16 rows have a maximum of 0.5 ulps over the whole
122
+ grid, 39 and 36 stay at or below 1 ulp. `exp`, `log`, `sqrt`, the trigonometric and hyperbolic
123
+ functions and their inverses, `erfc`, `erfinv`, `lgamma`, `digamma`, `i0`, `i1`, `i1e`, `elu`,
124
+ `selu`, `mish`, `softplus` and `logsigmoid` are all correctly rounded in both dtypes: they convert
125
+ to float, compute, and convert back once.
126
+
127
+ ## What the survey does not measure
128
+
129
+ One machine, CPU only, one build. 600 points per domain, so the all values scans quoted above for
130
+ `erf`, `logit` and `polygamma_2` were separate runs over every value of the dtype in the stated
131
+ interval, not part of `results.csv`. CUDA kernels are not measured. The half precision grids are
132
+ coarse at the top of their range (see the integer note above), which is also why the bfloat16
133
+ `polygamma_2` row cannot show the half integer problem.
@@ -0,0 +1,91 @@
1
+ function,backend,dtype,n,max_ulp,p99_ulp,median_ulp,frac_gt1,frac_gt10,max_abs_err,nonfinite_mismatch,worst_x,worst_got,worst_ref,vec_scalar_mismatch,default_tol_fail,op_tol_fail,op_rtol,op_atol,seconds
2
+ exp,torch,f16,577,0.49652399858703933,0.4877496877181343,0.0708642683168237,0.0,0.0,5.618725877364341,0,-0.0012197494506835938,0.9990234375,0.9987809941413149,0,0,0,0.001,1e-05,0.02
3
+ exp,torch,bf16,620,0.4974970990796693,0.47520794301700675,4.470348358154297e-08,0.0,0.0,1.5855092962538616e+33,0,-0.021728515625,0.9765625,0.97850584804328,0,0,0,0.016,1e-05,0.03
4
+ exp2,torch,f16,577,0.4962890576058865,0.49205187864370914,0.06404980535758294,0.0,0.0,5.911688801792479,0,0.0006990432739257812,1.0,1.0004846572828183,0,0,0,0.001,1e-05,0.02
5
+ exp2,torch,bf16,617,0.4889077724274732,0.48072804765681126,8.876224730507275e-09,0.0,0.0,1.003981677138867e+32,0,-0.01422119140625,0.98828125,0.9901910459860448,0,0,0,0.016,1e-05,0.03
6
+ expm1,torch,f16,577,0.49730118760972325,0.49034771682641204,0.04686579643374022,0.0,0.0,4.618725877364341,0,0.039947509765625,0.040740966796875,0.040756143224719536,0,0,0,0.001,1e-05,0.03
7
+ expm1,torch,bf16,620,0.4853231448379511,0.4672336336794082,1.4028955774656958e-08,0.0,0.0,1.5855092962538616e+33,0,-0.431640625,-0.349609375,-0.35055727176726165,0,0,0,0.016,1e-05,0.04
8
+ log,torch,f16,571,0.4999053175932843,0.49424945169839446,0.25053770135421477,0.0,0.0,0.005092666561314019,0,3.12109375,1.1376953125,1.138183501286712,0,0,0,0.001,1e-05,0.03
9
+ log,torch,bf16,615,0.49900858890093847,0.49542647977390203,0.25221120721920237,0.0,0.0,0.24950429445047462,0,2.1122164116337979e-38,-87.0,-86.75049570554953,0,0,0,0.016,0.05,0.03
10
+ log2,torch,f16,571,0.49982244041977186,0.4957887013732117,0.24917759192167044,0.0,0.0,0.007716188891969011,0,27184.0,14.734375,14.73047013718422,0,0,0,0.001,1e-05,0.03
11
+ log2,torch,bf16,615,0.49984227461230096,0.49631140505807564,0.24992113730615048,0.0,0.0,0.4594316186372964,0,4.4994390158148434e-18,-57.5,-57.62496056865307,0,0,0,0.016,0.1,0.03
12
+ log10,torch,f16,571,0.49963245913465204,0.4903260309973072,0.2422109430332955,0.0,0.0,0.0019428033816639712,0,0.0159454345703125,-1.7978515625,-1.7973636401766264,0,0,0,0.001,1e-05,0.03
13
+ log10,torch,bf16,615,0.4998269941082355,0.4948880258445741,0.24490373120930514,0.0,0.0,0.12395643537827539,0,3.651923115891872e+28,28.625,28.56252162573647,0,0,0,0.016,0.05,0.03
14
+ log1p,torch,f16,571,0.4995147834324868,0.49338139163683464,0.17714651543802104,0.0,0.0,0.0038929874031676803,0,0.07012939453125,0.06781005859375,0.06777957063089401,0,0,0,0.001,1e-05,0.03
15
+ log1p,torch,bf16,615,0.4983324042823015,0.48845749265665506,0.04134085372358378,0.0,0.0,0.24828420141527374,0,3.37944351430359e+22,51.75,51.87458310107058,0,0,0,0.016,0.1,0.03
16
+ sqrt,torch,f16,571,0.4999389499380398,0.49007737105917587,0.24356979992962996,0.0,0.0,0.06249236874225517,0,0.99951171875,0.99951171875,0.9997558295653994,0,0,0,0.001,1e-05,0.02
17
+ sqrt,torch,bf16,615,0.499510762740992,0.49902723367208435,0.2612480950072464,0.0,0.0,3.599354375916544e+16,0,1.1990042378387333e-35,3.4558944247975454e-18,3.462664057974341e-18,0,0,0,0.016,0.07,0.03
18
+ rsqrt,torch,f16,571,0.948287752861986,0.4995526197759731,0.2426170559979162,0.0,0.0,0.8267026007069944,0,29824.0,0.005786895751953125,0.005790513182650993,128,0,0,0.001,0.05,0.03
19
+ rsqrt,torch,bf16,615,1.0782885165447518,0.4993185592317671,0.2564640308922517,0.0016260162601626016,0.0,5.716504393996698e+16,0,1.010213276796536e+38,9.994988777600744e-20,9.949321482592776e-20,184,0,0,0.016,1e-05,0.03
20
+ reciprocal,torch,f16,588,0.49975574010747437,0.49818181818181817,0.21811460258780038,0.0,0.0,11.026506024099945,1,0.007808685302734375,128.125,128.06253053248656,0,0,0,0.001,1e-05,0.02
21
+ reciprocal,torch,bf16,619,0.4980392156862745,0.49751396316102214,0.23943661971830985,0.0,0.0,5.596749455936647e+35,1,-33423360.0,-3.003515303134918e-08,-2.991919424019608e-08,0,0,0,0.016,1e-05,0.02
22
+ sin,torch,f16,588,0.4996588404833843,0.4945322035448394,0.08753395421070723,0.0,0.0,0.0002419961642482482,0,-0.418212890625,-0.40625,-0.4061280129783976,0,0,0,0.001,1e-05,0.03
23
+ sin,torch,bf16,620,0.49902617601409,0.48721123707134933,0.024317169873750665,0.0,0.0,0.001949321000055071,0,-4544.0,-0.953125,-0.9511756789999449,0,0,0,0.016,0.01,0.03
24
+ cos,torch,f16,588,0.49845340422660517,0.4956050200685431,0.09112808529822407,0.0,0.0,0.00024338545128255173,0,-37568.0,0.6708984375,0.6711418229512826,0,0,0,0.001,1e-05,0.02
25
+ cos,torch,bf16,620,0.4982183001878292,0.47264074304242,0.052667672036868424,0.0,0.0,0.00194616523510871,0,-15.0625,-0.796875,-0.7988211652351087,0,0,0,0.016,0.01,0.03
26
+ tan,torch,f16,588,0.49881488045603833,0.4914911839161815,0.08113939790216393,0.0,0.0,0.017764182039798015,0,-0.028411865234375,-0.0284271240234375,-0.028419512712395387,0,0,0,0.001,1e-05,0.03
27
+ tan,torch,bf16,620,0.49997112617668704,0.4875677336521684,0.04762034554969279,0.0,0.0,0.11281124397999065,0,-248.0,0.1884765625,0.18798830944709308,0,0,0,0.016,1e-05,0.03
28
+ asin,torch,f16,648,0.4941364115688654,0.4890526633905064,0.009329841781712579,0.0,0.0,0.0004825550894227426,0,-0.99951171875,-1.5390625,-1.5395450550894227,0,0,0,0.001,1e-05,0.04
29
+ asin,torch,bf16,662,0.4903648339847289,0.47865063368268224,1.127157265195468e-06,0.0,0.0,0.0037394580756460183,0,-0.1435546875,-0.14453125,-0.1440523780918118,0,0,0,0.016,0.01,0.03
30
+ acos,torch,f16,648,0.4998616549945954,0.49918054207310525,0.3402882157076168,0.0,0.0,0.0009668216433849075,0,-4.589557647705078e-06,1.5712890625,1.5708009163525443,0,0,0,0.001,0.01,0.03
31
+ acos,torch,bf16,662,0.49946004853325654,0.48679677796885956,0.06253255191473825,0.0,0.0,0.007723588354033417,0,0.703125,0.7890625,0.791013515814583,0,0,0,0.016,0.1,0.03
32
+ atan,torch,f16,588,0.4992192365768905,0.49369285920882655,0.10639318712486037,0.0,0.0,0.0004838466629295546,0,-0.028411865234375,-0.0283966064453125,-0.02840422392633937,0,0,0,0.001,1e-05,0.02
33
+ atan,torch,bf16,620,0.4965529153521348,0.47865676775623917,0.030024177423035394,0.0,0.0,0.0038793196511885952,0,-8.75,-1.453125,-1.4570043196511886,0,0,0,0.016,0.01,0.03
34
+ sinh,torch,f16,577,0.49732908474709986,0.4746697418863143,1.5251472540330284e-05,0.0,0.0,15.33758697706071,0,-3.3203125,-13.8203125,-13.816427116525412,0,0,0,0.001,0.01,0.02
35
+ sinh,torch,bf16,620,0.4788486391066387,0.43272709337056176,3.102249621785879e-18,0.0,0.0,7.927546481269308e+32,0,-35.25,-1020346790576128.0,-1018240791989558.1,0,0,0,0.016,1e-05,0.03
36
+ cosh,torch,f16,577,0.49670313581569203,0.4866177109694043,3.419863079152353e-05,0.0,0.0,15.337576687445107,0,-0.09375,1.0048828125,1.00439775084393,0,0,0,0.001,1e-05,0.02
37
+ cosh,torch,bf16,618,0.49961859403523684,0.4890192345539579,6.899470525787083e-06,0.0,0.0,2.593927829559106e+34,0,-4.65625,52.75,52.62509535149119,0,0,0,0.016,1e-05,0.03
38
+ tanh,torch,f16,565,0.4968461339304618,0.4728154092331018,0.00037039433914303285,0.0,0.0,0.0002260244619315399,0,-0.05157470703125,-0.051544189453125,-0.051529026912416676,0,0,0,0.001,1e-05,0.02
39
+ tanh,torch,bf16,619,0.49394065721331387,0.4158991837313057,1.1847957170688265e-17,0.0,0.0,0.0019294556922394568,0,-1.8046875,-0.94921875,-0.9472892943077605,0,0,0,0.016,0.01,0.03
40
+ asinh,torch,f16,588,0.49726901812367386,0.485833174223409,0.06690126703671712,0.0,0.0,0.003734970759392553,0,-0.045166015625,-0.045135498046875,-0.04515067349298473,0,0,0,0.001,1e-05,0.03
41
+ asinh,torch,bf16,622,0.49695720494730633,0.49049542780111755,0.13255825285142203,0.0,0.0,0.2484786024736536,0,-1.5966312839994595e+35,-82.0,-81.75152139752635,0,0,0,0.016,0.05,0.03
42
+ acosh,torch,f16,494,0.4988606428465956,0.4929749887821485,0.24133997218624037,0.0,0.0,0.003897348772239795,0,9024.0,9.8046875,9.80079015122776,0,0,0,0.001,1e-05,0.02
43
+ acosh,torch,bf16,595,0.4987632823816887,0.4923519073210921,0.2587197539399728,0.0,0.0,0.24685276677669776,0,50855936.0,18.5,18.437654589702287,0,0,0,0.016,0.05,0.03
44
+ atanh,torch,f16,648,0.49854056428787036,0.4888009692464037,0.013543825964255069,0.0,0.0,0.0013952518564153138,0,-0.98583984375,-2.47265625,-2.4716825379603753,0,0,0,0.001,1e-05,0.03
45
+ atanh,torch,bf16,662,0.49854328708069856,0.4774971482177477,2.2543145421625954e-06,0.0,0.0,0.0068152048981477975,0,-0.431640625,-0.4609375,-0.4619112173575795,0,0,0,0.016,0.01,0.03
46
+ erf,torch,f16,556,4.554008308720993,3.9606023515251345,0.36747878381461374,0.2446043165467626,0.0,0.0002343458794934472,0,-3.4570693969726562e-06,-4.172325134277344e-06,-3.900885086731851e-06,0,0,0,0.001,0.01,0.03
47
+ erf,torch,bf16,619,253.8853125964903,241.47314175843889,0.4011357235244519,0.345718901453958,0.2455573505654281,0.001888891120270908,0,-1.3096723705530167e-08,-0.0,-1.4778070186526183e-08,0,0,0,0.016,0.01,0.03
48
+ erfc,torch,f16,563,0.49941349865129464,0.49188257526419277,0.0921491285628032,0.0,0.0,0.0004877084947767507,0,-0.33154296875,1.3603515625,1.3608392709947768,0,0,0,0.001,0.01,0.03
49
+ erfc,torch,bf16,619,0.4990151959322128,0.48589553314533057,0.010950456983912267,0.0,0.0,0.003898556218220328,0,-0.09375,1.109375,1.1054764437817797,0,0,0,0.016,0.01,0.04
50
+ erfinv,torch,f16,648,0.499711282699754,0.4963725486861071,0.24345604528932485,0.0,0.0,0.0009112087227549637,0,-0.984375,-1.708984375,-1.7094723742995115,0,0,0,0.001,0.01,0.27
51
+ erfinv,torch,bf16,662,0.49853190518721646,0.49689033519167136,0.2345729315275233,0.0,0.0,0.006422985394390679,0,-0.0419921875,-0.037353515625,-0.037231803734085155,0,0,0,0.016,0.01,0.23
52
+ lgamma,torch,f16,588,0.49855249039133065,0.49142581178497385,0.19514052288979372,0.0,0.0,15.447817746615328,0,-0.55224609375,1.2763671875,1.2758803198336022,0,0,0,0.001,0.7,0.04
53
+ lgamma,torch,bf16,616,0.4991600213797292,0.4921353382997607,0.2136705084395268,0.0,0.0,1799.9055113499053,0,-0.00049591064453125,7.625,7.609401249331883,0,0,0,0.016,1e-05,0.04
54
+ digamma,torch,f16,588,0.49909345681262235,0.49319664738344154,0.14984071040633115,0.0,0.0,11.603681000764482,1,0.0003020763397216797,-3310.0,-3310.9981869136254,0,0,0,0.001,0.5,0.06
55
+ digamma,torch,bf16,620,0.4980392156862745,0.4926691600549886,0.1755873052660539,0.0,0.0,5.233181085766195e+33,1,1.0799670077492329e-19,-9.295429630892704e+18,-9.259542123273814e+18,0,0,0,0.016,1e-05,0.06
56
+ sigmoid,torch,f16,569,0.4995072238814441,0.49611778689062863,0.07485496826868755,0.0,0.0,0.00024390001166085806,0,7.21875,0.99951171875,0.9992678187383391,0,0,0,0.001,0.01,0.03
57
+ sigmoid,torch,bf16,619,0.7324025492357978,0.4965613536741928,0.015380859300971217,0.0,0.0,0.0019531002499254546,0,-92.5,0.0,6.726055149644708e-41,0,0,0,0.016,0.01,0.03
58
+ i0,torch,f16,567,0.4980641717544879,0.4810795082375317,0.00021057227777656481,0.0,0.0,7.726867658057017,0,-0.33251953125,1.0283203125,1.027833921707271,0,0,0,0.001,1e-05,0.06
59
+ i0,torch,bf16,619,0.4966370950157683,0.4818175297966319,2.772361190232269e-05,0.0,0.0,7.244326886666297e+29,0,-0.70703125,1.1328125,1.1289325226951894,0,0,0,0.016,1e-05,0.06
60
+ i0e,torch,f16,588,1.4580990190361116,0.7490650014782869,0.17596994104951222,0.003401360544217687,0.0,0.0002436430109009624,0,54400.0,0.0017118453979492188,0.0017104548463639868,303,0,0,0.001,0.3,0.11
61
+ i0e,torch,bf16,620,0.6481236314694578,0.4971856378121076,0.1216757309092941,0.0,0.0,0.0019515878602806014,0,724992.0,0.0004673004150390625,0.0004685366127614392,413,0,0,0.016,0.3,0.16
62
+ i1,torch,f16,567,0.5000001700996843,0.4999999999999796,0.04735283585266004,0.0,0.0,5.632916459231637,0,-5.453824996948242e-05,-2.7239322662353516e-05,-2.726912499487994e-05,0,0,0,0.001,1e-05,0.06
63
+ i1,torch,bf16,619,0.5,0.4887155677084712,2.099691547751623e-05,0.0,0.0,4.653187276137042e+30,0,-9.183549615799121e-41,-0.0,-4.591774807899561e-41,0,0,0,0.016,1e-05,0.07
64
+ i1e,torch,f16,588,0.4999999701976787,0.4999986326697982,0.23838889927140242,0.0,0.0,6.1009957499358336e-05,0,-5.960464477539063e-08,-0.0,-2.980232061133854e-08,0,0,0,0.001,1e-05,0.1
65
+ i1e,torch,bf16,620,0.5,0.482013289876223,0.11544587685223048,0.0,0.0,0.00047008773643925084,0,-9.183549615799121e-41,-0.0,-4.591774807899561e-41,0,0,0,0.016,1e-05,0.11
66
+ logit,torch,f16,575,71.98646013347366,7.128095961116031,0.285489468988363,0.07130434782608695,0.008695652173913044,0.004545946250987143,0,0.497314453125,-0.01129150390625,-0.01074229080098363,0,29,0,0.001,0.5,0.03
67
+ logit,torch,bf16,480,64.0006510476272,5.753001711505866,0.2887366319272604,0.0625,0.004166666666666667,0.24954241196000737,0,0.498046875,-0.00390625,-0.007812539736793652,0,10,0,0.016,0.5,0.02
68
+ sinc,torch,f16,588,1.0,1.0,0.059106073512140145,0.0,0.0,0.00024115754367781683,0,-37568.0,5.960464477539063e-08,0.0,0,0,0,0.001,1e-05,0.03
69
+ sinc,torch,bf16,616,8.366493961506314e+32,6.591783121186793e+32,0.05288922090080902,0.24675324675324675,0.24675324675324675,0.0018124671372343748,0,-1352.0,7.683411240577698e-08,0.0,0,0,0,0.016,1e-05,0.03
70
+ entr,torch,f16,571,1.1911701490793096,0.941464544697664,0.231875189432804,0.0035026269702276708,0.0,27.97501637348614,0,3088.0,-24832.0,-24812.941277614733,0,0,0,0.001,0.1,0.02
71
+ entr,torch,bf16,608,1.2041861399076887,1.0059213428202278,0.30769754676849176,0.013157894736842105,0.0,2528.1952394642867,0,6.716849298982197e-15,2.2026824808563106e-13,2.1919871594286306e-13,0,0,0,0.016,0.1,0.03
72
+ polygamma_1,torch,f16,588,0.5313563672898688,0.4812044346716291,0.03925370341215999,0.0,0.0,12.837055171883549,0,-27.140625,53.9375,53.95410488647781,0,0,0,0.001,1e-05,0.28
73
+ polygamma_1,torch,bf16,616,0.49804144352119323,0.491512863022444,0.21772804902178775,0.0,0.0,3.9146045550699396e+33,75,2.015625,0.640625,0.6386795256112453,0,0,0,0.1,10.0,0.26
74
+ polygamma_2,torch,f16,588,14.045201776369824,7.387401080132452,0.0,0.013605442176870748,0.006802721088435374,13.40193968929816,0,-578.5,-2.1457672119140625e-06,-2.982926474593271e-06,0,0,0,0.001,1e-05,0.3
75
+ polygamma_2,torch,bf16,616,1.2061074283109008,0.4984591141373135,0.2007174268790859,0.0016233766233766235,0.0,4.2978092811015023e+21,0,-110.5,-8.058547973632812e-05,-8.116059657493157e-05,0,0,0,0.1,10.0,0.28
76
+ gelu,torch,f16,565,1.1881916773348211,0.499999854473665,0.20044231985055688,0.005309734513274336,0.0,0.0009315074694753456,0,-5.5703125,-0.0,-7.082174285261757e-08,3,0,0,0.001,1e-05,0.05
77
+ gelu,torch,bf16,618,241.6946820417233,155.95439972661566,0.011518837421012803,0.024271844660194174,0.021035598705501618,0.00770458022777154,0,-7.875,-0.0,-1.3416750046608877e-14,0,0,0,0.016,1e-05,0.06
78
+ gelu_tanh,torch,f16,565,0.9071118194365897,0.4999999933419324,0.19785984246498592,0.0,0.0,0.0008413279348808977,0,-5.20703125,-0.0,-5.406807776907621e-08,0,0,0,0.001,1e-05,0.04
79
+ gelu_tanh,torch,bf16,618,250.04118844059732,163.29967685968398,0.010957276982555794,0.01779935275080906,0.016181229773462782,0.007754819576731631,0,-9.125,-0.0,-1.23279823909867e-29,0,0,0,0.016,1e-05,0.05
80
+ silu,torch,f16,569,0.5000000149011612,0.49999938428401947,0.1983509299786978,0.0,0.0,0.0020256671500202827,0,5.960464477539063e-08,0.0,2.980232327587373e-08,0,0,0,0.001,1e-05,0.03
81
+ silu,torch,bf16,619,67.7472358043113,0.49195979713031013,0.024109840208281073,0.0016155088852988692,0.0016155088852988692,0.014749840050201968,0,-92.5,-0.0,-6.221601013421355e-39,0,0,0,0.016,1e-05,0.03
82
+ mish,torch,f16,569,0.4999120478296914,0.48618690812981913,0.2010713378968312,0.0,0.0,0.0016890522381167727,0,0.4521484375,0.333251953125,0.33337400196480216,0,0,0,0.001,0.01,0.04
83
+ mish,torch,bf16,619,0.49449324044528936,0.4857935599377371,0.20385758177384955,0.0,0.0,0.007381023396877406,0,0.00112152099609375,0.000675201416015625,0.0006733150740034283,0,0,0,0.016,1e-05,0.04
84
+ softplus,torch,f16,577,0.49851656125264876,0.4927780320059944,0.2876126008884409,0.0,0.0,0.001748125916124721,0,1.056640625,1.35546875,1.3549819174206517,0,0,0,0.01,0.01,0.03
85
+ softplus,torch,bf16,618,0.4996284353988572,0.49560855289998085,0.42088462033541374,0.0,0.0,0.013653602756594552,0,0.00042724609375,0.6953125,0.6933608264242233,0,0,0,0.016,0.01,0.04
86
+ logsigmoid,torch,f16,577,0.49851656125264876,0.4939507931537791,0.2876126008884409,0.0,0.0,0.001748125916124721,0,-1.056640625,-1.35546875,-1.3549819174206517,0,0,0,0.001,0.01,0.03
87
+ logsigmoid,torch,bf16,618,0.4996284353988572,0.49560855289998085,0.42088462033541374,0.0,0.0,0.013653602756594552,0,-0.00042724609375,-0.6953125,-0.6933608264242233,0,0,0,0.016,0.005,0.04
88
+ elu,torch,f16,569,0.4993940605685672,0.4719907161479319,0.0,0.0,0.0,0.00024384475613703493,0,-7.21875,-0.9990234375,-0.999267282256137,0,0,0,0.001,1e-05,0.03
89
+ elu,torch,bf16,619,0.49681778446169805,0.4637805853750317,0.0,0.0,0.0,0.0019304541362277217,0,-0.056884765625,-0.05517578125,-0.0552970746544096,0,0,0,0.016,1e-05,0.03
90
+ selu,torch,f16,569,0.4992712076423498,0.49346596296490464,0.26541042774774526,0.0,0.0,0.02847055252087216,0,-0.1016845703125,-0.169921875,-0.16998282119233915,0,0,0,0.001,1e-05,0.04
91
+ selu,torch,bf16,619,0.4982157977990872,0.4950991039854694,0.19653120297821333,0.0,0.0,0.22652257062782155,0,-0.09765625,-0.1630859375,-0.16357247636503816,0,0,0,0.016,1e-05,0.04
@@ -0,0 +1,105 @@
1
+ # Accuracy survey
2
+
3
+ Max error in ulps of the dtype against mpmath at 200 bits, about 60 decimal digits (p99 in brackets), on log spaced inputs over each function's domain plus the named edge values of the dtype. The reference is evaluated at the rounded input, so the numbers measure the implementation and not the conditioning of the function. An error is |got - exact| divided by the spacing of the dtype at the exact value, which is why an exact result of zero or a result in the subnormal range gives enormous numbers: read those rows together with the notes in README.md next to this file.
4
+
5
+ Versions: ulpwise 0.3.1, numpy 2.2.6, torch 2.14.0+cpu, scipy 1.18.1, mpmath 1.3.0, torch cpu capability AVX512
6
+
7
+ torch columns: `vec!=scalar` is the number of inputs where the vectorized kernel and the scalar tail disagree; `default fail` and `op fail` count inputs that fail torch's reference test tolerance for the dtype, with the default tolerance and with the op's own override respectively. A row with `default fail > 0` and `op fail = 0` is an error that torch's test suite tolerates because of the override.
8
+
9
+ | function | dtype | torch max (p99) | torch vec!=scalar | torch default fail | torch op fail | op (rtol, atol) |
10
+ |---|---|---|---|---|---|---|
11
+ | exp | bf16 | 0.5 (0.48) | 0 | 0 | 0 | (0.016, 1e-05) |
12
+ | exp | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
13
+ | exp2 | bf16 | 0.49 (0.48) | 0 | 0 | 0 | (0.016, 1e-05) |
14
+ | exp2 | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
15
+ | expm1 | bf16 | 0.49 (0.47) | 0 | 0 | 0 | (0.016, 1e-05) |
16
+ | expm1 | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
17
+ | log | bf16 | 0.5 (0.5) | 0 | 0 | 0 | (0.016, 0.05) |
18
+ | log | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
19
+ | log2 | bf16 | 0.5 (0.5) | 0 | 0 | 0 | (0.016, 0.1) |
20
+ | log2 | f16 | 0.5 (0.5) | 0 | 0 | 0 | (0.001, 1e-05) |
21
+ | log10 | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 0.05) |
22
+ | log10 | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
23
+ | log1p | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 0.1) |
24
+ | log1p | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
25
+ | sqrt | bf16 | 0.5 (0.5) | 0 | 0 | 0 | (0.016, 0.07) |
26
+ | sqrt | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
27
+ | rsqrt | bf16 | 1.1 (0.5) | 184 | 0 | 0 | (0.016, 1e-05) |
28
+ | rsqrt | f16 | 0.95 (0.5) | 128 | 0 | 0 | (0.001, 0.05) |
29
+ | reciprocal | bf16 | 0.5 (0.5) +1 nonfinite | 0 | 0 | 0 | (0.016, 1e-05) |
30
+ | reciprocal | f16 | 0.5 (0.5) +1 nonfinite | 0 | 0 | 0 | (0.001, 1e-05) |
31
+ | sin | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 0.01) |
32
+ | sin | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
33
+ | cos | bf16 | 0.5 (0.47) | 0 | 0 | 0 | (0.016, 0.01) |
34
+ | cos | f16 | 0.5 (0.5) | 0 | 0 | 0 | (0.001, 1e-05) |
35
+ | tan | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 1e-05) |
36
+ | tan | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
37
+ | asin | bf16 | 0.49 (0.48) | 0 | 0 | 0 | (0.016, 0.01) |
38
+ | asin | f16 | 0.49 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
39
+ | acos | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 0.1) |
40
+ | acos | f16 | 0.5 (0.5) | 0 | 0 | 0 | (0.001, 0.01) |
41
+ | atan | bf16 | 0.5 (0.48) | 0 | 0 | 0 | (0.016, 0.01) |
42
+ | atan | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
43
+ | sinh | bf16 | 0.48 (0.43) | 0 | 0 | 0 | (0.016, 1e-05) |
44
+ | sinh | f16 | 0.5 (0.47) | 0 | 0 | 0 | (0.001, 0.01) |
45
+ | cosh | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 1e-05) |
46
+ | cosh | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
47
+ | tanh | bf16 | 0.49 (0.42) | 0 | 0 | 0 | (0.016, 0.01) |
48
+ | tanh | f16 | 0.5 (0.47) | 0 | 0 | 0 | (0.001, 1e-05) |
49
+ | asinh | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 0.05) |
50
+ | asinh | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
51
+ | acosh | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 0.05) |
52
+ | acosh | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
53
+ | atanh | bf16 | 0.5 (0.48) | 0 | 0 | 0 | (0.016, 0.01) |
54
+ | atanh | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
55
+ | erf | bf16 | 254 (241) | 0 | 0 | 0 | (0.016, 0.01) |
56
+ | erf | f16 | 4.6 (4) | 0 | 0 | 0 | (0.001, 0.01) |
57
+ | erfc | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 0.01) |
58
+ | erfc | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 0.01) |
59
+ | erfinv | bf16 | 0.5 (0.5) | 0 | 0 | 0 | (0.016, 0.01) |
60
+ | erfinv | f16 | 0.5 (0.5) | 0 | 0 | 0 | (0.001, 0.01) |
61
+ | lgamma | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 1e-05) |
62
+ | lgamma | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 0.7) |
63
+ | digamma | bf16 | 0.5 (0.49) +1 nonfinite | 0 | 0 | 0 | (0.016, 1e-05) |
64
+ | digamma | f16 | 0.5 (0.49) +1 nonfinite | 0 | 0 | 0 | (0.001, 0.5) |
65
+ | sigmoid | bf16 | 0.73 (0.5) | 0 | 0 | 0 | (0.016, 0.01) |
66
+ | sigmoid | f16 | 0.5 (0.5) | 0 | 0 | 0 | (0.001, 0.01) |
67
+ | i0 | bf16 | 0.5 (0.48) | 0 | 0 | 0 | (0.016, 1e-05) |
68
+ | i0 | f16 | 0.5 (0.48) | 0 | 0 | 0 | (0.001, 1e-05) |
69
+ | i0e | bf16 | 0.65 (0.5) | 413 | 0 | 0 | (0.016, 0.3) |
70
+ | i0e | f16 | 1.5 (0.75) | 303 | 0 | 0 | (0.001, 0.3) |
71
+ | i1 | bf16 | 0.5 (0.49) | 0 | 0 | 0 | (0.016, 1e-05) |
72
+ | i1 | f16 | 0.5 (0.5) | 0 | 0 | 0 | (0.001, 1e-05) |
73
+ | i1e | bf16 | 0.5 (0.48) | 0 | 0 | 0 | (0.016, 1e-05) |
74
+ | i1e | f16 | 0.5 (0.5) | 0 | 0 | 0 | (0.001, 1e-05) |
75
+ | logit | bf16 | 64 (5.8) | 0 | 10 | 0 | (0.016, 0.5) |
76
+ | logit | f16 | 72 (7.1) | 0 | 29 | 0 | (0.001, 0.5) |
77
+ | sinc | bf16 | 8.4e+32 (6.6e+32) | 0 | 0 | 0 | (0.016, 1e-05) |
78
+ | sinc | f16 | 1 (1) | 0 | 0 | 0 | (0.001, 1e-05) |
79
+ | entr | bf16 | 1.2 (1) | 0 | 0 | 0 | (0.016, 0.1) |
80
+ | entr | f16 | 1.2 (0.94) | 0 | 0 | 0 | (0.001, 0.1) |
81
+ | polygamma_1 | bf16 | 0.5 (0.49) +75 nonfinite | 0 | 0 | 0 | (0.1, 10) |
82
+ | polygamma_1 | f16 | 0.53 (0.48) | 0 | 0 | 0 | (0.001, 1e-05) |
83
+ | polygamma_2 | bf16 | 1.2 (0.5) | 0 | 0 | 0 | (0.1, 10) |
84
+ | polygamma_2 | f16 | 14 (7.4) | 0 | 0 | 0 | (0.001, 1e-05) |
85
+ | gelu | bf16 | 242 (156) | 0 | 0 | 0 | (0.016, 1e-05) |
86
+ | gelu | f16 | 1.2 (0.5) | 3 | 0 | 0 | (0.001, 1e-05) |
87
+ | gelu_tanh | bf16 | 250 (163) | 0 | 0 | 0 | (0.016, 1e-05) |
88
+ | gelu_tanh | f16 | 0.91 (0.5) | 0 | 0 | 0 | (0.001, 1e-05) |
89
+ | silu | bf16 | 68 (0.49) | 0 | 0 | 0 | (0.016, 1e-05) |
90
+ | silu | f16 | 0.5 (0.5) | 0 | 0 | 0 | (0.001, 1e-05) |
91
+ | mish | bf16 | 0.49 (0.49) | 0 | 0 | 0 | (0.016, 1e-05) |
92
+ | mish | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 0.01) |
93
+ | softplus | bf16 | 0.5 (0.5) | 0 | 0 | 0 | (0.016, 0.01) |
94
+ | softplus | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.01, 0.01) |
95
+ | logsigmoid | bf16 | 0.5 (0.5) | 0 | 0 | 0 | (0.016, 0.005) |
96
+ | logsigmoid | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 0.01) |
97
+ | elu | bf16 | 0.5 (0.46) | 0 | 0 | 0 | (0.016, 1e-05) |
98
+ | elu | f16 | 0.5 (0.47) | 0 | 0 | 0 | (0.001, 1e-05) |
99
+ | selu | bf16 | 0.5 (0.5) | 0 | 0 | 0 | (0.016, 1e-05) |
100
+ | selu | f16 | 0.5 (0.49) | 0 | 0 | 0 | (0.001, 1e-05) |
101
+
102
+ ## Errors tolerated by a torch override
103
+
104
+ - `logit` f16: 29 of 575 inputs fail the default tolerance, none fail the op's (rtol 0.001, atol 0.5); worst x = 0.497314453125, got -0.01129150390625, exact -0.01074229080098363 (72 ulp).
105
+ - `logit` bf16: 10 of 480 inputs fail the default tolerance, none fail the op's (rtol 0.016, atol 0.5); worst x = 0.498046875, got -0.00390625, exact -0.007812539736793652 (64 ulp).
@@ -217,6 +217,9 @@ def test_every_reference_agrees_with_the_libraries_it_measures(entry):
217
217
  ("lgamma", -2.0, math.inf),
218
218
  ("lgamma", -2.5, "torch"),
219
219
  ("digamma", -2.0, None), # torch returns nan at the poles
220
+ ("polygamma_1", -2.0, math.inf), # the pole of an odd order is +inf from both sides
221
+ ("polygamma_1", 0.0, math.inf),
222
+ ("polygamma_2", -2.0, -math.inf), # an even order takes the sign of its formula, as scipy, torch and jax do
220
223
  ("erfinv", 1.0, math.inf),
221
224
  ("erfinv", -1.0, -math.inf),
222
225
  ("ndtri", 0.0, -math.inf),
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes