diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c6336d..715bd5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,18 @@ name: Fable.Python All notable changes to this project will be documented in this file. +## 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) + ## 5.0.0-rc.3 - 2026-04-16 ### 🐞 Bug Fixes diff --git a/src/stdlib/Math.fs b/src/stdlib/Math.fs index ea415a4..857d783 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: 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 + /// 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: '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 + + // ======================================================================== + // 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..a8b3ae5 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,108 @@ 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 + +[] +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