From 8ef0d3d352d1d00116de6dbc721f2e37c914e715 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 16 Apr 2026 05:59:52 +0000
Subject: [PATCH 1/2] fix(math): fix factorial signature and add missing
constants/functions
- Fix math.factorial: float -> float changed to int -> int for Python 3.12+
compatibility (float args raise TypeError since Python 3.12)
- Add missing constants: pi, e, tau, inf, nan
- Add missing functions: sqrt, degrees, radians, trunc, hypot, fsum,
isqrt, prod, perm, acosh, asinh, atanh, cosh, sinh, tanh, erf, erfc,
gamma, lgamma
- Fix math.dist signature to accept float arrays (multi-dimensional)
- Add tests for all new additions
- Update tests to use integer literals for factorial
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
CHANGELOG.md | 12 +++++
src/stdlib/Math.fs | 132 +++++++++++++++++++++++++++++++++++++++++----
test/TestMath.fs | 51 +++++++++++++++++-
3 files changed, 183 insertions(+), 12 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7c6336d..bc2e0f3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,18 @@ All notable changes to this project will be documented in this file.
* Bump Fable.Core to 5.0.0-rc.2 and ShipIt to 2.0.2 (#243) ([cb06fd6](https://github.com/fable-compiler/Fable.Python/commit/cb06fd6fc338fde73e8eb3c3720ed20bfdd17287))
+## Unreleased
+
+### 🐞 Bug Fixes
+
+* Fix `math.factorial` binding: changed signature from `float -> float` to `int -> int` to match Python 3.12+ where float arguments raise `TypeError`. Fixes test to use integer literals.
+
+### ✨ Enhancements
+
+* Add missing `math` module constants: `pi`, `e`, `tau`, `inf`, `nan`
+* Add missing `math` module functions: `sqrt`, `degrees`, `radians`, `trunc`, `hypot`, `fsum`, `isqrt`, `prod`, `perm`, `acosh`, `asinh`, `atanh`, `cosh`, `sinh`, `tanh`, `erf`, `erfc`, `gamma`, `lgamma`
+* Fix `math.dist` signature to accept float arrays (for multi-dimensional distance)
+
[View changes on Github](https://github.com/fable-compiler/Fable.Python/compare/8223cc8eb8b2dcaa02c1a19566c5ed5d73242b11..66e56764fefe824e1b2a28635245820c2dc92a34)
## 5.0.0-rc.2 - 2026-03-09
diff --git a/src/stdlib/Math.fs b/src/stdlib/Math.fs
index ea415a4..356fa8e 100644
--- a/src/stdlib/Math.fs
+++ b/src/stdlib/Math.fs
@@ -8,6 +8,30 @@ open Fable.Core
[]
type IExports =
+ // ========================================================================
+ // Constants
+ // ========================================================================
+
+ /// The mathematical constant π = 3.141592…
+ /// See https://docs.python.org/3/library/math.html#math.pi
+ abstract pi: float
+ /// The mathematical constant e = 2.718281…
+ /// See https://docs.python.org/3/library/math.html#math.e
+ abstract e: float
+ /// The mathematical constant τ = 6.283185… (2π)
+ /// See https://docs.python.org/3/library/math.html#math.tau
+ abstract tau: float
+ /// Floating-point positive infinity
+ /// See https://docs.python.org/3/library/math.html#math.inf
+ abstract inf: float
+ /// A floating-point "not a number" (NaN) value
+ /// See https://docs.python.org/3/library/math.html#math.nan
+ abstract nan: float
+
+ // ========================================================================
+ // Number-theoretic and representation functions
+ // ========================================================================
+
/// Return the ceiling of x as an integer
/// See https://docs.python.org/3/library/math.html#math.ceil
abstract ceil: x: int -> int
@@ -23,22 +47,48 @@ type IExports =
/// Return the absolute value of x
/// See https://docs.python.org/3/library/math.html#math.fabs
abstract fabs: x: float -> float
- /// Return the factorial of x
+ /// Return the factorial of n as an integer. Raises ValueError if n is negative.
+ /// Note: float arguments were deprecated in Python 3.9 and removed in Python 3.12.
/// See https://docs.python.org/3/library/math.html#math.factorial
- abstract factorial: x: float -> float
+ abstract factorial: n: int -> int
/// Return the floor of x as an integer
/// See https://docs.python.org/3/library/math.html#math.floor
abstract floor: x: int -> int
/// Return the floor of x as an integer
/// See https://docs.python.org/3/library/math.html#math.floor
abstract floor: x: float -> int
- /// Return the remainder of x / y
+ /// Return the floating-point remainder of x / y
/// See https://docs.python.org/3/library/math.html#math.fmod
abstract fmod: x: int -> y: int -> int
-
+ /// Return an accurate floating-point sum of values in the iterable
+ /// See https://docs.python.org/3/library/math.html#math.fsum
+ abstract fsum: iterable: IEnumerable -> float
/// Return the greatest common divisor of the integers
/// See https://docs.python.org/3/library/math.html#math.gcd
abstract gcd: [] ints: int[] -> int
+ /// Return the integer square root of the non-negative integer n
+ /// See https://docs.python.org/3/library/math.html#math.isqrt
+ abstract isqrt: n: int -> int
+ /// Return the least common multiple of the integers
+ /// See https://docs.python.org/3/library/math.html#math.lcm
+ abstract lcm: [] ints: int[] -> int
+ /// Return the number of ways to choose k items from n items without repetition and with order
+ /// See https://docs.python.org/3/library/math.html#math.perm
+ abstract perm: n: int -> int
+ /// Return the number of ways to choose k items from n items without repetition and with order
+ /// See https://docs.python.org/3/library/math.html#math.perm
+ abstract perm: n: int * k: int -> int
+ /// Return the product of all elements in the iterable
+ /// See https://docs.python.org/3/library/math.html#math.prod
+ abstract prod: iterable: IEnumerable<'T> -> 'T
+ /// Truncate x to an integer (towards zero)
+ /// See https://docs.python.org/3/library/math.html#math.trunc
+ abstract trunc: x: float -> int
+
+ // ========================================================================
+ // Floating-point predicates
+ // ========================================================================
+
/// Check if x is neither an infinity nor a NaN
/// See https://docs.python.org/3/library/math.html#math.isfinite
abstract isfinite: x: float -> bool
@@ -57,9 +107,10 @@ type IExports =
/// Check if x is a NaN (not a number)
/// See https://docs.python.org/3/library/math.html#math.isnan
abstract isnan: x: int -> bool
- /// Return the least common multiple of the integers
- /// See https://docs.python.org/3/library/math.html#math.lcm
- abstract lcm: [] ints: int[] -> int
+
+ // ========================================================================
+ // Power and logarithmic functions
+ // ========================================================================
/// Return e raised to the power of x
/// See https://docs.python.org/3/library/math.html#math.exp
@@ -82,6 +133,13 @@ type IExports =
/// Return x raised to the power y
/// See https://docs.python.org/3/library/math.html#math.pow
abstract pow: x: float -> y: float -> float
+ /// Return the square root of x
+ /// See https://docs.python.org/3/library/math.html#math.sqrt
+ abstract sqrt: x: float -> float
+
+ // ========================================================================
+ // Trigonometric functions
+ // ========================================================================
/// Return the arc cosine of x in radians
/// See https://docs.python.org/3/library/math.html#math.acos
@@ -98,15 +156,69 @@ type IExports =
/// Return the cosine of x radians
/// See https://docs.python.org/3/library/math.html#math.cos
abstract cos: x: float -> float
- /// Return the Euclidean distance between two points
- /// See https://docs.python.org/3/library/math.html#math.dist
- abstract dist: p: float -> q: float -> float
/// Return the sine of x radians
/// See https://docs.python.org/3/library/math.html#math.sin
abstract sin: x: float -> float
/// Return the tangent of x radians
/// See https://docs.python.org/3/library/math.html#math.tan
abstract tan: x: float -> float
+ /// Return the Euclidean norm of a sequence of coordinates
+ /// See https://docs.python.org/3/library/math.html#math.hypot
+ abstract hypot: [] coordinates: float[] -> float
+ /// Convert angle x from radians to degrees
+ /// See https://docs.python.org/3/library/math.html#math.degrees
+ abstract degrees: x: float -> float
+ /// Convert angle x from degrees to radians
+ /// See https://docs.python.org/3/library/math.html#math.radians
+ abstract radians: x: float -> float
+
+ // ========================================================================
+ // Hyperbolic functions
+ // ========================================================================
+
+ /// Return the inverse hyperbolic cosine of x
+ /// See https://docs.python.org/3/library/math.html#math.acosh
+ abstract acosh: x: float -> float
+ /// Return the inverse hyperbolic sine of x
+ /// See https://docs.python.org/3/library/math.html#math.asinh
+ abstract asinh: x: float -> float
+ /// Return the inverse hyperbolic tangent of x
+ /// See https://docs.python.org/3/library/math.html#math.atanh
+ abstract atanh: x: float -> float
+ /// Return the hyperbolic cosine of x
+ /// See https://docs.python.org/3/library/math.html#math.cosh
+ abstract cosh: x: float -> float
+ /// Return the hyperbolic sine of x
+ /// See https://docs.python.org/3/library/math.html#math.sinh
+ abstract sinh: x: float -> float
+ /// Return the hyperbolic tangent of x
+ /// See https://docs.python.org/3/library/math.html#math.tanh
+ abstract tanh: x: float -> float
+
+ // ========================================================================
+ // Special functions
+ // ========================================================================
+
+ /// Return the error function at x
+ /// See https://docs.python.org/3/library/math.html#math.erf
+ abstract erf: x: float -> float
+ /// Return the complementary error function at x
+ /// See https://docs.python.org/3/library/math.html#math.erfc
+ abstract erfc: x: float -> float
+ /// Return the Gamma function at x
+ /// See https://docs.python.org/3/library/math.html#math.gamma
+ abstract gamma: x: float -> float
+ /// Return the natural logarithm of the absolute value of the Gamma function at x
+ /// See https://docs.python.org/3/library/math.html#math.lgamma
+ abstract lgamma: x: float -> float
+
+ // ========================================================================
+ // Distance and geometry
+ // ========================================================================
+
+ /// Return the Euclidean distance between two points p and q
+ /// See https://docs.python.org/3/library/math.html#math.dist
+ abstract dist: p: float[] -> q: float[] -> float
/// Mathematical functions
[]
diff --git a/test/TestMath.fs b/test/TestMath.fs
index 759fc8f..1d4e25c 100644
--- a/test/TestMath.fs
+++ b/test/TestMath.fs
@@ -32,8 +32,8 @@ let ``test fabs works`` () =
[]
let ``test factorial works`` () =
- math.factorial 5.0 |> equal 120.0
- math.factorial 0.0 |> equal 1.0
+ math.factorial 5 |> equal 120
+ math.factorial 0 |> equal 1
[]
let ``test fmod works`` () =
@@ -119,3 +119,50 @@ let ``test atan works`` () =
[]
let ``test atan2 works`` () =
math.atan2 0.0 1.0 |> equal 0.0
+
+[]
+let ``test pi constant works`` () =
+ math.pi |> fun x -> (x > 3.14159 && x < 3.14160) |> equal true
+
+[]
+let ``test e constant works`` () =
+ math.e |> fun x -> (x > 2.71828 && x < 2.71829) |> equal true
+
+[]
+let ``test tau constant works`` () =
+ math.tau |> fun x -> (x > 6.28318 && x < 6.28319) |> equal true
+
+[]
+let ``test inf constant works`` () =
+ math.isinf math.inf |> equal true
+
+[]
+let ``test sqrt works`` () =
+ math.sqrt 4.0 |> equal 2.0
+ math.sqrt 9.0 |> equal 3.0
+
+[]
+let ``test degrees works`` () =
+ math.degrees math.pi |> fun x -> (x > 179.999 && x < 180.001) |> equal true
+
+[]
+let ``test radians works`` () =
+ math.radians 180.0 |> fun x -> (x > 3.14158 && x < 3.14160) |> equal true
+
+[]
+let ``test trunc works`` () =
+ math.trunc 2.7 |> equal 2
+ math.trunc -2.7 |> equal -2
+
+[]
+let ``test hypot works`` () =
+ math.hypot (3.0, 4.0) |> equal 5.0
+
+[]
+let ``test isqrt works`` () =
+ math.isqrt 16 |> equal 4
+ math.isqrt 17 |> equal 4
+
+[]
+let ``test fsum works`` () =
+ math.fsum [ 1.0; 2.0; 3.0 ] |> equal 6.0
From 0cafc81d7b5beeeb8eae4bd124d4da775d126b8c Mon Sep 17 00:00:00 2001
From: Dag Brattli
Date: Thu, 16 Apr 2026 08:12:00 +0200
Subject: [PATCH 2/2] fix(math): fix build error, add missing tests, fix
CHANGELOG order
Replace IEnumerable with seq in fsum/prod to fix build (missing
import). Add tests for nan, prod, perm, dist, hyperbolic functions,
and special functions. Move Unreleased section above rc.3 in CHANGELOG.
Co-Authored-By: Claude Opus 4.6 (1M context)
---
CHANGELOG.md | 12 +++++-----
src/stdlib/Math.fs | 4 ++--
test/TestMath.fs | 58 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 66 insertions(+), 8 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bc2e0f3..715bd5b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,12 +7,6 @@ name: Fable.Python
All notable changes to this project will be documented in this file.
-## 5.0.0-rc.3 - 2026-04-16
-
-### 🐞 Bug Fixes
-
-* Bump Fable.Core to 5.0.0-rc.2 and ShipIt to 2.0.2 (#243) ([cb06fd6](https://github.com/fable-compiler/Fable.Python/commit/cb06fd6fc338fde73e8eb3c3720ed20bfdd17287))
-
## Unreleased
### 🐞 Bug Fixes
@@ -25,6 +19,12 @@ All notable changes to this project will be documented in this file.
* Add missing `math` module functions: `sqrt`, `degrees`, `radians`, `trunc`, `hypot`, `fsum`, `isqrt`, `prod`, `perm`, `acosh`, `asinh`, `atanh`, `cosh`, `sinh`, `tanh`, `erf`, `erfc`, `gamma`, `lgamma`
* Fix `math.dist` signature to accept float arrays (for multi-dimensional distance)
+## 5.0.0-rc.3 - 2026-04-16
+
+### 🐞 Bug Fixes
+
+* Bump Fable.Core to 5.0.0-rc.2 and ShipIt to 2.0.2 (#243) ([cb06fd6](https://github.com/fable-compiler/Fable.Python/commit/cb06fd6fc338fde73e8eb3c3720ed20bfdd17287))
+
[View changes on Github](https://github.com/fable-compiler/Fable.Python/compare/8223cc8eb8b2dcaa02c1a19566c5ed5d73242b11..66e56764fefe824e1b2a28635245820c2dc92a34)
## 5.0.0-rc.2 - 2026-03-09
diff --git a/src/stdlib/Math.fs b/src/stdlib/Math.fs
index 356fa8e..857d783 100644
--- a/src/stdlib/Math.fs
+++ b/src/stdlib/Math.fs
@@ -62,7 +62,7 @@ type IExports =
abstract fmod: x: int -> y: int -> int
/// Return an accurate floating-point sum of values in the iterable
/// See https://docs.python.org/3/library/math.html#math.fsum
- abstract fsum: iterable: IEnumerable -> float
+ abstract fsum: iterable: float seq -> float
/// Return the greatest common divisor of the integers
/// See https://docs.python.org/3/library/math.html#math.gcd
abstract gcd: [] ints: int[] -> int
@@ -80,7 +80,7 @@ type IExports =
abstract perm: n: int * k: int -> int
/// Return the product of all elements in the iterable
/// See https://docs.python.org/3/library/math.html#math.prod
- abstract prod: iterable: IEnumerable<'T> -> 'T
+ abstract prod: iterable: 'T seq -> 'T
/// Truncate x to an integer (towards zero)
/// See https://docs.python.org/3/library/math.html#math.trunc
abstract trunc: x: float -> int
diff --git a/test/TestMath.fs b/test/TestMath.fs
index 1d4e25c..a8b3ae5 100644
--- a/test/TestMath.fs
+++ b/test/TestMath.fs
@@ -166,3 +166,61 @@ let ``test isqrt works`` () =
[]
let ``test fsum works`` () =
math.fsum [ 1.0; 2.0; 3.0 ] |> equal 6.0
+
+[]
+let ``test nan constant works`` () =
+ math.isnan math.nan |> equal true
+
+[]
+let ``test prod works`` () =
+ math.prod [ 1; 2; 3; 4 ] |> equal 24
+
+[]
+let ``test perm works`` () =
+ math.perm 5 |> equal 120
+ math.perm (5, 2) |> equal 20
+
+[]
+let ``test dist works`` () =
+ math.dist [| 0.0; 0.0 |] [| 3.0; 4.0 |] |> equal 5.0
+
+[]
+let ``test cosh works`` () =
+ math.cosh 0.0 |> equal 1.0
+
+[]
+let ``test sinh works`` () =
+ math.sinh 0.0 |> equal 0.0
+
+[]
+let ``test tanh works`` () =
+ math.tanh 0.0 |> equal 0.0
+
+[]
+let ``test acosh works`` () =
+ math.acosh 1.0 |> equal 0.0
+
+[]
+let ``test asinh works`` () =
+ math.asinh 0.0 |> equal 0.0
+
+[]
+let ``test atanh works`` () =
+ math.atanh 0.0 |> equal 0.0
+
+[]
+let ``test erf works`` () =
+ math.erf 0.0 |> equal 0.0
+
+[]
+let ``test erfc works`` () =
+ math.erfc 0.0 |> equal 1.0
+
+[]
+let ``test gamma works`` () =
+ math.gamma 1.0 |> equal 1.0
+ math.gamma 5.0 |> equal 24.0
+
+[]
+let ``test lgamma works`` () =
+ math.lgamma 1.0 |> equal 0.0