| ... | @@ -200,67 +200,69 @@ pub fn expectFmt(expected: []const u8, comptime template: []const u8, args: anyt | ... | @@ -200,67 +200,69 @@ pub fn expectFmt(expected: []const u8, comptime template: []const u8, args: anyt |
| 200 | return error.TestFailed; | 200 | return error.TestFailed; |
| 201 | } | 201 | } |
| 202 | | 202 | |
| 203 | /// This function is intended to be used only in tests. When the actual value is not | 203 | pub const expectWithinMargin = @compileError("expectWithinMargin is deprecated, use expectApproxEqAbs or expectApproxEqRel"); |
| 204 | /// within the margin of the expected value, | 204 | pub const expectWithinEpsilon = @compileError("expectWithinEpsilon is deprecated, use expectApproxEqAbs or expectApproxEqRel"); |
| 205 | /// prints diagnostics to stderr to show exactly how they are not equal, then aborts. | 205 | |
| | 206 | /// This function is intended to be used only in tests. When the actual value is |
| | 207 | /// not approximately equal to the expected value, prints diagnostics to stderr |
| | 208 | /// to show exactly how they are not equal, then aborts. |
| | 209 | /// See `math.approxEqAbs` for more informations on the tolerance parameter. |
| 206 | /// The types must be floating point | 210 | /// The types must be floating point |
| 207 | pub fn expectWithinMargin(expected: anytype, actual: @TypeOf(expected), margin: @TypeOf(expected)) void { | 211 | pub fn expectApproxEqAbs(expected: anytype, actual: @TypeOf(expected), tolerance: @TypeOf(expected)) void { |
| 208 | std.debug.assert(margin >= 0.0); | 212 | const T = @TypeOf(expected); |
| | 213 | |
| | 214 | switch (@typeInfo(T)) { |
| | 215 | .Float => if (!math.approxEqAbs(T, expected, actual, tolerance)) |
| | 216 | std.debug.panic("actual {}, not within absolute tolerance {} of expected {}", .{ actual, tolerance, expected }), |
| | 217 | |
| | 218 | .ComptimeFloat => @compileError("Cannot approximately compare two comptime_float values"), |
| 209 | | 219 | |
| 210 | switch (@typeInfo(@TypeOf(actual))) { | | |
| 211 | .Float, | | |
| 212 | .ComptimeFloat, | | |
| 213 | => { | | |
| 214 | if (@fabs(expected - actual) > margin) { | | |
| 215 | std.debug.panic("actual {}, not within margin {} of expected {}", .{ actual, margin, expected }); | | |
| 216 | } | | |
| 217 | }, | | |
| 218 | else => @compileError("Unable to compare non floating point values"), | 220 | else => @compileError("Unable to compare non floating point values"), |
| 219 | } | 221 | } |
| 220 | } | 222 | } |
| 221 | | 223 | |
| 222 | test "expectWithinMargin" { | 224 | test "expectApproxEqAbs" { |
| 223 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { | 225 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { |
| 224 | const pos_x: T = 12.0; | 226 | const pos_x: T = 12.0; |
| 225 | const pos_y: T = 12.06; | 227 | const pos_y: T = 12.06; |
| 226 | const neg_x: T = -12.0; | 228 | const neg_x: T = -12.0; |
| 227 | const neg_y: T = -12.06; | 229 | const neg_y: T = -12.06; |
| 228 | | 230 | |
| 229 | expectWithinMargin(pos_x, pos_y, 0.1); | 231 | expectApproxEqAbs(pos_x, pos_y, 0.1); |
| 230 | expectWithinMargin(neg_x, neg_y, 0.1); | 232 | expectApproxEqAbs(neg_x, neg_y, 0.1); |
| 231 | } | 233 | } |
| 232 | } | 234 | } |
| 233 | | 235 | |
| 234 | /// This function is intended to be used only in tests. When the actual value is not | 236 | /// This function is intended to be used only in tests. When the actual value is |
| 235 | /// within the epsilon of the expected value, | 237 | /// not approximately equal to the expected value, prints diagnostics to stderr |
| 236 | /// prints diagnostics to stderr to show exactly how they are not equal, then aborts. | 238 | /// to show exactly how they are not equal, then aborts. |
| | 239 | /// See `math.approxEqRel` for more informations on the tolerance parameter. |
| 237 | /// The types must be floating point | 240 | /// The types must be floating point |
| 238 | pub fn expectWithinEpsilon(expected: anytype, actual: @TypeOf(expected), epsilon: @TypeOf(expected)) void { | 241 | pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance: @TypeOf(expected)) void { |
| 239 | std.debug.assert(epsilon >= 0.0 and epsilon <= 1.0); | 242 | const T = @TypeOf(expected); |
| | 243 | |
| | 244 | switch (@typeInfo(T)) { |
| | 245 | .Float => if (!math.approxEqRel(T, expected, actual, tolerance)) |
| | 246 | std.debug.panic("actual {}, not within relative tolerance {} of expected {}", .{ actual, tolerance, expected }), |
| | 247 | |
| | 248 | .ComptimeFloat => @compileError("Cannot approximately compare two comptime_float values"), |
| 240 | | 249 | |
| 241 | // Relative epsilon test. | | |
| 242 | const margin = math.max(math.fabs(expected), math.fabs(actual)) * epsilon; | | |
| 243 | switch (@typeInfo(@TypeOf(actual))) { | | |
| 244 | .Float, | | |
| 245 | .ComptimeFloat, | | |
| 246 | => { | | |
| 247 | if (@fabs(expected - actual) > margin) { | | |
| 248 | std.debug.panic("actual {}, not within epsilon {}, of expected {}", .{ actual, epsilon, expected }); | | |
| 249 | } | | |
| 250 | }, | | |
| 251 | else => @compileError("Unable to compare non floating point values"), | 250 | else => @compileError("Unable to compare non floating point values"), |
| 252 | } | 251 | } |
| 253 | } | 252 | } |
| 254 | | 253 | |
| 255 | test "expectWithinEpsilon" { | 254 | test "expectApproxEqRel" { |
| 256 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { | 255 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { |
| | 256 | const eps_value = comptime math.epsilon(T); |
| | 257 | const sqrt_eps_value = comptime math.sqrt(eps_value); |
| | 258 | |
| 257 | const pos_x: T = 12.0; | 259 | const pos_x: T = 12.0; |
| 258 | const pos_y: T = 13.2; | 260 | const pos_y: T = pos_x + 2 * eps_value; |
| 259 | const neg_x: T = -12.0; | 261 | const neg_x: T = -12.0; |
| 260 | const neg_y: T = -13.2; | 262 | const neg_y: T = neg_x - 2 * eps_value; |
| 261 | | 263 | |
| 262 | expectWithinEpsilon(pos_x, pos_y, 0.1); | 264 | expectApproxEqRel(pos_x, pos_y, sqrt_eps_value); |
| 263 | expectWithinEpsilon(neg_x, neg_y, 0.1); | 265 | expectApproxEqRel(neg_x, neg_y, sqrt_eps_value); |
| 264 | } | 266 | } |
| 265 | } | 267 | } |
| 266 | | 268 | |