|
6 | 6 | "os" |
7 | 7 | "reflect" |
8 | 8 | "strconv" |
| 9 | + "strings" |
9 | 10 | "testing" |
10 | 11 |
|
11 | 12 | "github.com/ericlagergren/decimal" |
@@ -277,15 +278,15 @@ got : %v |
277 | 278 | func check(t *testing.T, z, r *decimal.Big, c *Case, flags decimal.Condition) { |
278 | 279 | helper(t)() |
279 | 280 | if !equal(z, r) { |
280 | | - str := fmt.Sprintf(`%s |
281 | | -wanted: %q (%s:%d) |
282 | | -got : %q (%s:%d) |
283 | | -`, |
| 281 | + s := []string{ |
284 | 282 | c.ShortString(10000), |
285 | | - r, flags, -r.Scale(), |
286 | | - z, z.Context.Conditions, -z.Scale(), |
287 | | - ) |
288 | | - t.Log(str) |
| 283 | + fmt.Sprintf("wanted: %q (%s:%d)", r, flags, -r.Scale()), |
| 284 | + fmt.Sprintf("got : %q (%s:%d)", z, z.Context.Conditions, -z.Scale()), |
| 285 | + } |
| 286 | + if allow1ULPError[c.Op] && equalWithin1ULP(z, r) { |
| 287 | + s = append(s, "passed within 1 ULP") |
| 288 | + } |
| 289 | + t.Log(strings.Join(s, "\n"), "\n") |
289 | 290 | } |
290 | 291 | } |
291 | 292 |
|
@@ -321,6 +322,35 @@ func equal(x, y *decimal.Big) bool { |
321 | 322 | return cmp && scl && prec |
322 | 323 | } |
323 | 324 |
|
| 325 | +func equalWithin1ULP(x, y *decimal.Big) bool { |
| 326 | + if !x.IsFinite() || !y.IsFinite() { |
| 327 | + return false |
| 328 | + } |
| 329 | + formX, negX, coeffX, expX := x.Decompose(make([]byte, 2<<3)) |
| 330 | + formY, negY, coeffY, expY := y.Decompose(make([]byte, 2<<3)) |
| 331 | + if formX != formY || negX != negY || expX != expY { |
| 332 | + return false |
| 333 | + } |
| 334 | + l := len(coeffX) |
| 335 | + if len(coeffY) != l { |
| 336 | + return false |
| 337 | + } |
| 338 | + for i := 0; i < l-1; i++ { |
| 339 | + if coeffX[i] != coeffY[i] { |
| 340 | + return false |
| 341 | + } |
| 342 | + } |
| 343 | + d := coeffX[l-1] - coeffY[l-1] |
| 344 | + return d == 0x01 || d == 0xff |
| 345 | +} |
| 346 | + |
| 347 | +var allow1ULPError = map[Op]bool{ |
| 348 | + Exp: true, |
| 349 | + Ln: true, |
| 350 | + Log10: true, |
| 351 | + Power: true, |
| 352 | +} |
| 353 | + |
324 | 354 | // helper returns testing.T.Helper, if it exists. |
325 | 355 | func helper(v interface{}) func() { |
326 | 356 | if fn, ok := v.(interface { |
|
0 commit comments