| ... | ... | @@ -200,67 +200,69 @@ pub fn expectFmt(expected: []const u8, comptime template: []const u8, args: anyt |
| 200 | 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 |
| 204 | | /// within the margin of the expected value, |
| 205 | | /// prints diagnostics to stderr to show exactly how they are not equal, then aborts. |
| 203 | pub const expectWithinMargin = @compileError("expectWithinMargin is deprecated, use expectApproxEqAbs or expectApproxEqRel"); |
| 204 | pub const expectWithinEpsilon = @compileError("expectWithinEpsilon is deprecated, use expectApproxEqAbs or expectApproxEqRel"); |
| 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 | 210 | /// The types must be floating point |
| 207 | | pub fn expectWithinMargin(expected: anytype, actual: @TypeOf(expected), margin: @TypeOf(expected)) void { |
| 208 | | std.debug.assert(margin >= 0.0); |
| 211 | pub fn expectApproxEqAbs(expected: anytype, actual: @TypeOf(expected), tolerance: @TypeOf(expected)) void { |
| 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 | 220 | else => @compileError("Unable to compare non floating point values"), |
| 219 | 221 | } |
| 220 | 222 | } |
| 221 | 223 | |
| 222 | | test "expectWithinMargin" { |
| 224 | test "expectApproxEqAbs" { |
| 223 | 225 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { |
| 224 | 226 | const pos_x: T = 12.0; |
| 225 | 227 | const pos_y: T = 12.06; |
| 226 | 228 | const neg_x: T = -12.0; |
| 227 | 229 | const neg_y: T = -12.06; |
| 228 | 230 | |
| 229 | | expectWithinMargin(pos_x, pos_y, 0.1); |
| 230 | | expectWithinMargin(neg_x, neg_y, 0.1); |
| 231 | expectApproxEqAbs(pos_x, pos_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 |
| 235 | | /// within the epsilon of the expected value, |
| 236 | | /// prints diagnostics to stderr to show exactly how they are not equal, then aborts. |
| 236 | /// This function is intended to be used only in tests. When the actual value is |
| 237 | /// not approximately equal to the expected value, prints diagnostics to stderr |
| 238 | /// to show exactly how they are not equal, then aborts. |
| 239 | /// See `math.approxEqRel` for more informations on the tolerance parameter. |
| 237 | 240 | /// The types must be floating point |
| 238 | | pub fn expectWithinEpsilon(expected: anytype, actual: @TypeOf(expected), epsilon: @TypeOf(expected)) void { |
| 239 | | std.debug.assert(epsilon >= 0.0 and epsilon <= 1.0); |
| 241 | pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance: @TypeOf(expected)) void { |
| 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 | 250 | else => @compileError("Unable to compare non floating point values"), |
| 252 | 251 | } |
| 253 | 252 | } |
| 254 | 253 | |
| 255 | | test "expectWithinEpsilon" { |
| 254 | test "expectApproxEqRel" { |
| 256 | 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 | 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 | 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); |
| 263 | | expectWithinEpsilon(neg_x, neg_y, 0.1); |
| 264 | expectApproxEqRel(pos_x, pos_y, sqrt_eps_value); |
| 265 | expectApproxEqRel(neg_x, neg_y, sqrt_eps_value); |
| 264 | 266 | } |
| 265 | 267 | } |
| 266 | 268 | |