Source file test/typeparam/absdiff3.go

     1  // run
     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  // absdiff example using a function argument rather than attaching an
     8  // Abs method to a structure containing base types.
     9  
    10  package main
    11  
    12  import (
    13  	"fmt"
    14  	"math"
    15  )
    16  
    17  type Numeric interface {
    18  	OrderedNumeric | Complex
    19  }
    20  
    21  // absDifference computes the absolute value of the difference of
    22  // a and b, where the absolute value is determined by the abs function.
    23  func absDifference[T Numeric](a, b T, abs func(a T) T) T {
    24  	return abs(a - b)
    25  }
    26  
    27  // OrderedNumeric matches numeric types that support the < operator.
    28  type OrderedNumeric interface {
    29  	~int | ~int8 | ~int16 | ~int32 | ~int64 |
    30  		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
    31  		~float32 | ~float64
    32  }
    33  
    34  func Abs[T OrderedNumeric](a T) T {
    35  	if a < 0 {
    36  		return -a
    37  	}
    38  	return a
    39  }
    40  
    41  // Complex matches the two complex types, which do not have a < operator.
    42  type Complex interface {
    43  	~complex64 | ~complex128
    44  }
    45  
    46  func realimag(x any) (re, im float64) {
    47  	switch z := x.(type) {
    48  	case complex64:
    49  		re = float64(real(z))
    50  		im = float64(imag(z))
    51  	case complex128:
    52  		re = real(z)
    53  		im = imag(z)
    54  	default:
    55  		panic("unknown complex type")
    56  	}
    57  	return
    58  }
    59  
    60  func ComplexAbs[T Complex](a T) T {
    61  	// TODO use direct conversion instead of realimag once #50937 is fixed
    62  	r, i := realimag(a)
    63  	// r := float64(real(a))
    64  	// i := float64(imag(a))
    65  	d := math.Sqrt(r*r + i*i)
    66  	return T(complex(d, 0))
    67  }
    68  
    69  // OrderedAbsDifference returns the absolute value of the difference
    70  // between a and b, where a and b are of an ordered type.
    71  func OrderedAbsDifference[T OrderedNumeric](a, b T) T {
    72  	return absDifference(a, b, Abs[T])
    73  }
    74  
    75  // ComplexAbsDifference returns the absolute value of the difference
    76  // between a and b, where a and b are of a complex type.
    77  func ComplexAbsDifference[T Complex](a, b T) T {
    78  	return absDifference(a, b, ComplexAbs[T])
    79  }
    80  
    81  func main() {
    82  	if got, want := OrderedAbsDifference(1.0, -2.0), 3.0; got != want {
    83  		panic(fmt.Sprintf("got = %v, want = %v", got, want))
    84  	}
    85  	if got, want := OrderedAbsDifference(-1.0, 2.0), 3.0; got != want {
    86  		panic(fmt.Sprintf("got = %v, want = %v", got, want))
    87  	}
    88  	if got, want := OrderedAbsDifference(-20, 15), 35; got != want {
    89  		panic(fmt.Sprintf("got = %v, want = %v", got, want))
    90  	}
    91  
    92  	if got, want := ComplexAbsDifference(5.0+2.0i, 2.0-2.0i), 5+0i; got != want {
    93  		panic(fmt.Sprintf("got = %v, want = %v", got, want))
    94  	}
    95  	if got, want := ComplexAbsDifference(2.0-2.0i, 5.0+2.0i), 5+0i; got != want {
    96  		panic(fmt.Sprintf("got = %v, want = %v", got, want))
    97  	}
    98  }
    99  

View as plain text