| ... | @@ -120,7 +120,7 @@ pub const epsilon = @compileError("Deprecated: use `floatEps` instead"); | ... | @@ -120,7 +120,7 @@ pub const epsilon = @compileError("Deprecated: use `floatEps` instead"); |
| 120 | /// | 120 | /// |
| 121 | /// NaN values are never considered equal to any value. | 121 | /// NaN values are never considered equal to any value. |
| 122 | pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool { | 122 | pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool { |
| 123 | assert(@typeInfo(T) == .Float); | 123 | assert(@typeInfo(T) == .Float or @typeInfo(T) == .ComptimeFloat); |
| 124 | assert(tolerance >= 0); | 124 | assert(tolerance >= 0); |
| 125 | | 125 | |
| 126 | // Fast path for equal values (and signed zeros and infinites). | 126 | // Fast path for equal values (and signed zeros and infinites). |
| ... | @@ -148,7 +148,7 @@ pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool { | ... | @@ -148,7 +148,7 @@ pub fn approxEqAbs(comptime T: type, x: T, y: T, tolerance: T) bool { |
| 148 | /// | 148 | /// |
| 149 | /// NaN values are never considered equal to any value. | 149 | /// NaN values are never considered equal to any value. |
| 150 | pub fn approxEqRel(comptime T: type, x: T, y: T, tolerance: T) bool { | 150 | pub fn approxEqRel(comptime T: type, x: T, y: T, tolerance: T) bool { |
| 151 | assert(@typeInfo(T) == .Float); | 151 | assert(@typeInfo(T) == .Float or @typeInfo(T) == .ComptimeFloat); |
| 152 | assert(tolerance > 0); | 152 | assert(tolerance > 0); |
| 153 | | 153 | |
| 154 | // Fast path for equal values (and signed zeros and infinites). | 154 | // Fast path for equal values (and signed zeros and infinites). |
| ... | @@ -184,6 +184,24 @@ test "approxEqAbs and approxEqRel" { | ... | @@ -184,6 +184,24 @@ test "approxEqAbs and approxEqRel" { |
| 184 | try testing.expect(approxEqAbs(T, min_value, 0.0, eps_value * 2)); | 184 | try testing.expect(approxEqAbs(T, min_value, 0.0, eps_value * 2)); |
| 185 | try testing.expect(approxEqAbs(T, -min_value, 0.0, eps_value * 2)); | 185 | try testing.expect(approxEqAbs(T, -min_value, 0.0, eps_value * 2)); |
| 186 | } | 186 | } |
| | 187 | |
| | 188 | comptime { |
| | 189 | // `comptime_float` is guaranteed to have the same precision and operations of |
| | 190 | // the largest other floating point type, which is f128 but it doesn't have a |
| | 191 | // defined layout so we can't rely on `@bitCast` to construct the smallest |
| | 192 | // possible epsilon value like we do in the tests above. In the same vein, we |
| | 193 | // also can't represent a max/min, `NaN` or `Inf` values. |
| | 194 | const eps_value = 1e-4; |
| | 195 | const sqrt_eps_value = sqrt(eps_value); |
| | 196 | |
| | 197 | try testing.expect(approxEqAbs(comptime_float, 0.0, 0.0, eps_value)); |
| | 198 | try testing.expect(approxEqAbs(comptime_float, -0.0, -0.0, eps_value)); |
| | 199 | try testing.expect(approxEqAbs(comptime_float, 0.0, -0.0, eps_value)); |
| | 200 | try testing.expect(approxEqRel(comptime_float, 1.0, 1.0, sqrt_eps_value)); |
| | 201 | try testing.expect(!approxEqRel(comptime_float, 1.0, 0.0, sqrt_eps_value)); |
| | 202 | try testing.expect(!approxEqAbs(comptime_float, 1.0 + 2 * eps_value, 1.0, eps_value)); |
| | 203 | try testing.expect(approxEqAbs(comptime_float, 1.0 + 1 * eps_value, 1.0, eps_value)); |
| | 204 | } |
| 187 | } | 205 | } |
| 188 | | 206 | |
| 189 | pub const doNotOptimizeAway = @compileError("Deprecated: use `std.mem.doNotOptimizeAway` instead"); | 207 | pub const doNotOptimizeAway = @compileError("Deprecated: use `std.mem.doNotOptimizeAway` instead"); |