github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/runtime/minmax_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime_test 6 7 import ( 8 "math" 9 "strings" 10 "testing" 11 "unsafe" 12 ) 13 14 var ( 15 zero = math.Copysign(0, +1) 16 negZero = math.Copysign(0, -1) 17 inf = math.Inf(+1) 18 negInf = math.Inf(-1) 19 nan = math.NaN() 20 ) 21 22 var tests = []struct{ min, max float64 }{ 23 {1, 2}, 24 {-2, 1}, 25 {negZero, zero}, 26 {zero, inf}, 27 {negInf, zero}, 28 {negInf, inf}, 29 {1, inf}, 30 {negInf, 1}, 31 } 32 33 var all = []float64{1, 2, -1, -2, zero, negZero, inf, negInf, nan} 34 35 func eq(x, y float64) bool { 36 return x == y && math.Signbit(x) == math.Signbit(y) 37 } 38 39 func TestMinFloat(t *testing.T) { 40 for _, tt := range tests { 41 if z := min(tt.min, tt.max); !eq(z, tt.min) { 42 t.Errorf("min(%v, %v) = %v, want %v", tt.min, tt.max, z, tt.min) 43 } 44 if z := min(tt.max, tt.min); !eq(z, tt.min) { 45 t.Errorf("min(%v, %v) = %v, want %v", tt.max, tt.min, z, tt.min) 46 } 47 } 48 for _, x := range all { 49 if z := min(nan, x); !math.IsNaN(z) { 50 t.Errorf("min(%v, %v) = %v, want %v", nan, x, z, nan) 51 } 52 if z := min(x, nan); !math.IsNaN(z) { 53 t.Errorf("min(%v, %v) = %v, want %v", nan, x, z, nan) 54 } 55 } 56 } 57 58 func TestMaxFloat(t *testing.T) { 59 for _, tt := range tests { 60 if z := max(tt.min, tt.max); !eq(z, tt.max) { 61 t.Errorf("max(%v, %v) = %v, want %v", tt.min, tt.max, z, tt.max) 62 } 63 if z := max(tt.max, tt.min); !eq(z, tt.max) { 64 t.Errorf("max(%v, %v) = %v, want %v", tt.max, tt.min, z, tt.max) 65 } 66 } 67 for _, x := range all { 68 if z := max(nan, x); !math.IsNaN(z) { 69 t.Errorf("max(%v, %v) = %v, want %v", nan, x, z, nan) 70 } 71 if z := max(x, nan); !math.IsNaN(z) { 72 t.Errorf("max(%v, %v) = %v, want %v", nan, x, z, nan) 73 } 74 } 75 } 76 77 // testMinMax tests that min/max behave correctly on every pair of 78 // values in vals. 79 // 80 // vals should be a sequence of values in strictly ascending order. 81 func testMinMax[T int | uint8 | string](t *testing.T, vals ...T) { 82 for i, x := range vals { 83 for _, y := range vals[i+1:] { 84 if !(x < y) { 85 t.Fatalf("values out of order: !(%v < %v)", x, y) 86 } 87 88 if z := min(x, y); z != x { 89 t.Errorf("min(%v, %v) = %v, want %v", x, y, z, x) 90 } 91 if z := min(y, x); z != x { 92 t.Errorf("min(%v, %v) = %v, want %v", y, x, z, x) 93 } 94 95 if z := max(x, y); z != y { 96 t.Errorf("max(%v, %v) = %v, want %v", x, y, z, y) 97 } 98 if z := max(y, x); z != y { 99 t.Errorf("max(%v, %v) = %v, want %v", y, x, z, y) 100 } 101 } 102 } 103 } 104 105 func TestMinMaxInt(t *testing.T) { testMinMax[int](t, -7, 0, 9) } 106 func TestMinMaxUint8(t *testing.T) { testMinMax[uint8](t, 0, 1, 2, 4, 7) } 107 func TestMinMaxString(t *testing.T) { testMinMax[string](t, "a", "b", "c") } 108 109 // TestMinMaxStringTies ensures that min(a, b) returns a when a == b. 110 func TestMinMaxStringTies(t *testing.T) { 111 s := "xxx" 112 x := strings.Split(s, "") 113 114 test := func(i, j, k int) { 115 if z := min(x[i], x[j], x[k]); unsafe.StringData(z) != unsafe.StringData(x[i]) { 116 t.Errorf("min(x[%v], x[%v], x[%v]) = %p, want %p", i, j, k, unsafe.StringData(z), unsafe.StringData(x[i])) 117 } 118 if z := max(x[i], x[j], x[k]); unsafe.StringData(z) != unsafe.StringData(x[i]) { 119 t.Errorf("max(x[%v], x[%v], x[%v]) = %p, want %p", i, j, k, unsafe.StringData(z), unsafe.StringData(x[i])) 120 } 121 } 122 123 test(0, 1, 2) 124 test(0, 2, 1) 125 test(1, 0, 2) 126 test(1, 2, 0) 127 test(2, 0, 1) 128 test(2, 1, 0) 129 } 130 131 func BenchmarkMinFloat(b *testing.B) { 132 var m float64 = 0 133 for i := 0; i < b.N; i++ { 134 for _, f := range all { 135 m = min(m, f) 136 } 137 } 138 } 139 140 func BenchmarkMaxFloat(b *testing.B) { 141 var m float64 = 0 142 for i := 0; i < b.N; i++ { 143 for _, f := range all { 144 m = max(m, f) 145 } 146 } 147 }