commit a73f5e017dfd686e9f352af0c63e20ba84ea6751
parent be7f7251890fabad7f5567361b9fb8bbf7f64307
Author: Sebastian <sebastian@sebsite.pw>
Date: Sun, 1 Dec 2024 20:25:20 -0500
math: merge isclose with eqwithin
Now that we have optional parameters, we can get rid of eqwithin, and
instead use STANDARD_TOL as the default tol argument.
This is a breaking change.
Signed-off-by: Sebastian <sebastian@sebsite.pw>
Diffstat:
4 files changed, 49 insertions(+), 69 deletions(-)
diff --git a/math/+test/floats_test.ha b/math/+test/floats_test.ha
@@ -174,7 +174,7 @@
for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) {
let res = modfracf64(TEST_INPUTS[idx]);
assert(res.0 == TEST_MODFRAC[idx].0);
- assert(isclose(res.1, TEST_MODFRAC[idx].1));
+ assert(isclosef64(res.1, TEST_MODFRAC[idx].1));
};
let res = modfracf64(1.75f64);
assert(res.0 == 1f64);
diff --git a/math/+test/math_test.ha b/math/+test/math_test.ha
@@ -1,18 +1,18 @@
// SPDX-License-Identifier: MPL-2.0
// (c) Hare authors <https://harelang.org>
-@test fn eqwithin() void = {
- assert(eqwithin(1f64, 2f64, 2f64));
- assert(eqwithin(1.0f32, 2.0f32, 2.0f32));
- assert(!eqwithin(1.0005f32, 1.0004f32, 0.00001f32));
- assert(isclose(1f64, 1.0000000000000000000000000001f64));
- assert(isclose(1.0f32, 1.0000000000000000000000000001f32));
- assert(!isclose(1.0005f32, 1.0004f32));
+@test fn isclose() void = {
+ assert(isclose(1f64, 2f64, 2f64));
+ assert(isclose(1.0f32, 2.0f32, 2.0f32));
+ assert(!isclose(1.0005f32, 1.0004f32, 0.00001f32));
+ assert(isclosef64(1f64, 1.0000000000000000000000000001f64));
+ assert(isclosef32(1.0f32, 1.0000000000000000000000000001f32));
+ assert(!isclosef32(1.0005f32, 1.0004f32));
};
@test fn logf64() void = {
for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) {
- assert(isclose(
+ assert(isclosef64(
logf64(absf64(TEST_INPUTS[idx])),
TEST_LOG[idx]));
};
@@ -26,7 +26,7 @@
@test fn log10f64() void = {
for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) {
- assert(isclose(
+ assert(isclosef64(
log10f64(absf64(TEST_INPUTS[idx])),
TEST_LOG10[idx]));
};
@@ -34,7 +34,7 @@
@test fn log2f64() void = {
for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) {
- assert(isclose(
+ assert(isclosef64(
log2f64(absf64(TEST_INPUTS[idx])),
TEST_LOG2[idx]));
};
@@ -42,7 +42,7 @@
@test fn log1p() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
log1pf64(TEST_INPUTS[idx] / 100f64),
TEST_LOG1P[idx]));
};
@@ -57,7 +57,7 @@
@test fn expf64() void = {
for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) {
- assert(isclose(expf64(TEST_INPUTS[idx]), TEST_EXP[idx]));
+ assert(isclosef64(expf64(TEST_INPUTS[idx]), TEST_EXP[idx]));
};
assert(expf64(1f64) == E);
assert(isnan(expf64(NAN)));
@@ -70,7 +70,7 @@
@test fn exp2f64() void = {
for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) {
- assert(isclose(exp2f64(TEST_INPUTS[idx]), TEST_EXP2[idx]));
+ assert(isclosef64(exp2f64(TEST_INPUTS[idx]), TEST_EXP2[idx]));
};
assert(exp2f64(0f64) == 1f64);
assert(exp2f64(3f64) == 8f64);
@@ -85,7 +85,7 @@
@test fn sqrt() void = {
for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) {
- assert(isclose(
+ assert(isclosef64(
sqrtf64(absf64(TEST_INPUTS[idx])),
TEST_SQRT[idx]));
};
@@ -102,7 +102,7 @@
@test fn powf64() void = {
for (let idx = 0z; idx < len(TEST_INPUTS); idx += 1) {
- assert(eqwithin(
+ assert(isclosef64(
powf64(10f64, TEST_INPUTS[idx]),
TEST_POW[idx],
1e-8f64));
@@ -126,17 +126,17 @@
assert(powf64(2f64, -F64_MAX_NORMAL) == 0f64);
assert(isinf(powf64(0.5f64, -F64_MAX_NORMAL)));
// Positive fractional powers
- assert(eqwithin(powf64(2f64, 1.5f64),
+ assert(isclosef64(powf64(2f64, 1.5f64),
2.8284271247461900976033774f64,
1e-10f64));
- assert(eqwithin(powf64(2f64, 5.5f64),
+ assert(isclosef64(powf64(2f64, 5.5f64),
45.254833995939041561654039f64,
1e-10f64));
// Negative fractional powers
- assert(eqwithin(powf64(2f64, -1.5f64),
+ assert(isclosef64(powf64(2f64, -1.5f64),
0.3535533905932737622004221f64,
1e-10f64));
- assert(eqwithin(powf64(2f64, -5.5f64),
+ assert(isclosef64(powf64(2f64, -5.5f64),
0.0220970869120796101375263f64,
1e-10f64));
@@ -200,7 +200,7 @@
@test fn floor() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
floorf64(TEST_INPUTS[idx]),
TEST_FLOOR[idx]));
};
@@ -213,7 +213,7 @@
@test fn ceil() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
ceilf64(TEST_INPUTS[idx]),
TEST_CEIL[idx]));
};
@@ -228,7 +228,7 @@
@test fn trunc() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
truncf64(TEST_INPUTS[idx]),
TEST_TRUNC[idx]));
};
@@ -243,7 +243,7 @@
@test fn round() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
roundf64(TEST_INPUTS[idx]),
TEST_ROUND[idx]));
};
@@ -258,7 +258,7 @@
@test fn modf64() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
modf64(10f64, TEST_INPUTS[idx]),
TEST_MODF[idx]));
};
diff --git a/math/+test/trig_test.ha b/math/+test/trig_test.ha
@@ -7,7 +7,7 @@
const j = reduced.0;
const z = reduced.1;
const xred = (j: i64: f64) * (PI / 4f64) + z;
- assert(isclose(
+ assert(isclosef64(
sinf64(TEST_INPUTS[idx]),
sinf64(xred)));
};
@@ -15,7 +15,7 @@
@test fn cos() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
cosf64(TEST_INPUTS[idx]), TEST_COS[idx]));
};
assert(isnan(cosf64(-INF)));
@@ -25,7 +25,7 @@
@test fn sin() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
sinf64(TEST_INPUTS[idx]), TEST_SIN[idx]));
};
assert(isnan(sinf64(-INF)));
@@ -37,7 +37,7 @@
@test fn tan() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
tanf64(TEST_INPUTS[idx]), TEST_TAN[idx]));
};
assert(isnan(sinf64(-INF)));
@@ -49,7 +49,7 @@
@test fn asin() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
asinf64(TEST_INPUTS[idx] / 10f64),
TEST_ASIN[idx]));
};
@@ -62,7 +62,7 @@
@test fn acos() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
acosf64(TEST_INPUTS[idx] / 10f64),
TEST_ACOS[idx]));
};
@@ -74,7 +74,7 @@
@test fn atan() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
atanf64(TEST_INPUTS[idx]),
TEST_ATAN[idx]));
};
@@ -87,7 +87,7 @@
@test fn sinh() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(eqwithin(
+ assert(isclosef64(
sinhf64(TEST_INPUTS[idx]),
TEST_SINH[idx],
1e-6f64));
@@ -101,7 +101,7 @@
@test fn cosh() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
coshf64(TEST_INPUTS[idx]),
TEST_COSH[idx]));
};
@@ -114,7 +114,7 @@
@test fn tanh() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
tanhf64(TEST_INPUTS[idx]),
TEST_TANH[idx]));
};
@@ -127,7 +127,7 @@
@test fn asinh() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
asinhf64(TEST_INPUTS[idx]),
TEST_ASINH[idx]));
};
@@ -140,7 +140,7 @@
@test fn acosh() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
acoshf64(1f64 + absf64(TEST_INPUTS[idx])),
TEST_ACOSH[idx]));
};
@@ -153,7 +153,7 @@
@test fn atanh() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
atanhf64(TEST_INPUTS[idx] / 10f64),
TEST_ATANH[idx]));
};
@@ -170,7 +170,7 @@
@test fn atan2() void = {
for (let idx = 0z; idx < 10; idx += 1) {
- assert(isclose(
+ assert(isclosef64(
atan2f64(10f64, TEST_INPUTS[idx]),
TEST_ATAN2[idx]));
};
@@ -196,7 +196,7 @@
@test fn hypot() void = {
for (let idx = 0z; idx < 10; idx += 1) {
const a = absf64(1e200f64 * TEST_TANH[idx] * SQRT_2);
- assert(isclose(
+ assert(isclosef64(
hypotf64(1e200f64 * TEST_TANH[idx],
1e200f64 * TEST_TANH[idx]),
a));
diff --git a/math/math.ha b/math/math.ha
@@ -49,13 +49,13 @@
use types;
-// The standard tolerance used by isclose(), which is just an arbitrary way to
-// measure whether two floating-point numbers are "sufficiently" close to each
-// other.
-export def STANDARD_TOL: f64 = 1e-14;
+// The standard tolerance used by [[isclosef32]] and [[isclosef64]], which is
+// just an arbitrary way to measure whether two floating-point numbers are
+// "sufficiently" close to each other.
+export def STANDARD_TOL = 1e-14;
// Returns whether x and y are within tol of each other.
-export fn eqwithinf64(x: f64, y: f64, tol: f64) bool = {
+export fn isclosef64(x: f64, y: f64, tol: f64 = STANDARD_TOL) bool = {
if (isnan(x) || isnan(y) || isnan(tol)) {
return false;
};
@@ -63,7 +63,7 @@ export fn eqwithinf64(x: f64, y: f64, tol: f64) bool = {
};
// Returns whether x and y are within tol of each other.
-export fn eqwithinf32(x: f32, y: f32, tol: f32) bool = {
+export fn isclosef32(x: f32, y: f32, tol: f32 = STANDARD_TOL) bool = {
if (isnan(x) || isnan(y) || isnan(tol)) {
return false;
};
@@ -71,36 +71,16 @@ export fn eqwithinf32(x: f32, y: f32, tol: f32) bool = {
};
// Returns whether x and y are within tol of each other.
-export fn eqwithin(
+export fn isclose(
x: types::floating,
y: types::floating,
tol: types::floating,
) bool = {
match (x) {
case let n: f64 =>
- return eqwithinf64(n, y as f64, tol as f64);
+ return isclosef64(n, y as f64, tol as f64);
case let n: f32 =>
- return eqwithinf32(n, y as f32, tol as f32);
- };
-};
-
-// Returns whether x and y are within [[STANDARD_TOL]] of each other.
-export fn isclosef64(x: f64, y: f64) bool = {
- return eqwithinf64(x, y, STANDARD_TOL);
-};
-
-// Returns whether x and y are within [[STANDARD_TOL]] of each other.
-export fn isclosef32(x: f32, y: f32) bool = {
- return eqwithinf32(x, y, STANDARD_TOL: f32);
-};
-
-// Returns whether x and y are within [[STANDARD_TOL]] of each other.
-export fn isclose(x: types::floating, y: types::floating) bool = {
- match (x) {
- case let n: f64 =>
- return isclosef64(n, y as f64);
- case let n: f32 =>
- return isclosef32(n, y as f32);
+ return isclosef32(n, y as f32, tol as f32);
};
};