|
| 1 | +// run -gcflags=-G=3 |
| 2 | + |
| 3 | +// Copyright 2022 The Go Authors. All rights reserved. |
| 4 | +// Use of this source code is governed by a BSD-style |
| 5 | +// license that can be found in the LICENSE file. |
| 6 | + |
| 7 | +package main |
| 8 | + |
| 9 | +import ( |
| 10 | + "fmt" |
| 11 | + "math" |
| 12 | +) |
| 13 | + |
| 14 | +type Numeric interface { |
| 15 | + ~int | ~int8 | ~int16 | ~int32 | ~int64 | |
| 16 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | |
| 17 | + ~float32 | ~float64 | |
| 18 | + ~complex64 | ~complex128 |
| 19 | +} |
| 20 | + |
| 21 | +// numericAbs matches a struct containing a numeric type that has an Abs method. |
| 22 | +type numericAbs[T Numeric] interface { |
| 23 | + ~struct{ Value T } |
| 24 | + Abs() T |
| 25 | +} |
| 26 | + |
| 27 | +// AbsDifference computes the absolute value of the difference of |
| 28 | +// a and b, where the absolute value is determined by the Abs method. |
| 29 | +func absDifference[T Numeric, U numericAbs[T]](a, b U) T { |
| 30 | + d := a.Value - b.Value |
| 31 | + dt := U{Value: d} |
| 32 | + return dt.Abs() |
| 33 | +} |
| 34 | + |
| 35 | +// orderedNumeric matches numeric types that support the < operator. |
| 36 | +type orderedNumeric interface { |
| 37 | + ~int | ~int8 | ~int16 | ~int32 | ~int64 | |
| 38 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | |
| 39 | + ~float32 | ~float64 |
| 40 | +} |
| 41 | + |
| 42 | +// Complex matches the two complex types, which do not have a < operator. |
| 43 | +type Complex interface { |
| 44 | + ~complex64 | ~complex128 |
| 45 | +} |
| 46 | + |
| 47 | +// orderedAbs is a helper type that defines an Abs method for |
| 48 | +// a struct containing an ordered numeric type. |
| 49 | +type orderedAbs[T orderedNumeric] struct { |
| 50 | + Value T |
| 51 | +} |
| 52 | + |
| 53 | +func (a orderedAbs[T]) Abs() T { |
| 54 | + if a.Value < 0 { |
| 55 | + return -a.Value |
| 56 | + } |
| 57 | + return a.Value |
| 58 | +} |
| 59 | + |
| 60 | +// complexAbs is a helper type that defines an Abs method for |
| 61 | +// a struct containing a complex type. |
| 62 | +type complexAbs[T Complex] struct { |
| 63 | + Value T |
| 64 | +} |
| 65 | + |
| 66 | +func (a complexAbs[T]) Abs() T { |
| 67 | + r := float64(real(a.Value)) |
| 68 | + i := float64(imag(a.Value)) |
| 69 | + d := math.Sqrt(r*r + i*i) |
| 70 | + return T(complex(d, 0)) |
| 71 | +} |
| 72 | + |
| 73 | +// OrderedAbsDifference returns the absolute value of the difference |
| 74 | +// between a and b, where a and b are of an ordered type. |
| 75 | +func OrderedAbsDifference[T orderedNumeric](a, b T) T { |
| 76 | + return absDifference(orderedAbs[T]{a}, orderedAbs[T]{b}) |
| 77 | +} |
| 78 | + |
| 79 | +// ComplexAbsDifference returns the absolute value of the difference |
| 80 | +// between a and b, where a and b are of a complex type. |
| 81 | +func ComplexAbsDifference[T Complex](a, b T) T { |
| 82 | + return absDifference(complexAbs[T]{a}, complexAbs[T]{b}) |
| 83 | +} |
| 84 | + |
| 85 | +func main() { |
| 86 | + if got, want := OrderedAbsDifference(1.0, -2.0), 3.0; got != want { |
| 87 | + panic(fmt.Sprintf("got = %v, want = %v", got, want)) |
| 88 | + } |
| 89 | + if got, want := OrderedAbsDifference(-1.0, 2.0), 3.0; got != want { |
| 90 | + panic(fmt.Sprintf("got = %v, want = %v", got, want)) |
| 91 | + } |
| 92 | + if got, want := OrderedAbsDifference(-20, 15), 35; got != want { |
| 93 | + panic(fmt.Sprintf("got = %v, want = %v", got, want)) |
| 94 | + } |
| 95 | + |
| 96 | + if got, want := ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want { |
| 97 | + panic(fmt.Sprintf("got = %v, want = %v", got, want)) |
| 98 | + } |
| 99 | + if got, want := ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want { |
| 100 | + panic(fmt.Sprintf("got = %v, want = %v", got, want)) |
| 101 | + } |
| 102 | +} |
0 commit comments