Skip to content

Commit

Permalink
udpate Max Min MinMax function to support float64, deprecated corresp…
Browse files Browse the repository at this point in the history
…onding float64 version function
  • Loading branch information
suchen-sci committed Aug 26, 2023
1 parent 07a61bf commit 8e652f5
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 81 deletions.
37 changes: 23 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@
- [gfn.DivMod](#gfndivmod)
- [gfn.Max](#gfnmax)
- [gfn.MaxBy](#gfnmaxby)
- [gfn.MaxFloat64](#gfnmaxfloat64)
- [gfn.MaxFloat64 (Deprecated)](#gfnmaxfloat64-deprecated)
- [gfn.Mean](#gfnmean)
- [gfn.MeanBy](#gfnmeanby)
- [gfn.Min](#gfnmin)
- [gfn.MinBy](#gfnminby)
- [gfn.MinFloat64](#gfnminfloat64)
- [gfn.MinFloat64 (Deprecated)](#gfnminfloat64-deprecated)
- [gfn.MinMax](#gfnminmax)
- [gfn.MinMaxBy](#gfnminmaxby)
- [gfn.MinMaxFloat64](#gfnminmaxfloat64)
- [gfn.MinMaxFloat64 (Deprecated)](#gfnminmaxfloat64-deprecated)
- [gfn.Mode](#gfnmode)
- [gfn.ModeBy](#gfnmodeby)
- [gfn.Sum](#gfnsum)
Expand Down Expand Up @@ -270,14 +270,17 @@ gfn.DivMod(10, 3) // (3, 1)

### gfn.Max
```go
func Max[T Int | Uint | ~float32 | ~string](array ...T) T
func Max[T Int | Uint | Float | ~string](array ...T) T
```
Max returns the maximum value in the array. For float64 arrays, please use MaxFloat64. NaN value in float64 arrays is not comparable to other values. Which means Max([math.NaN(), 0.5]) produces math.NaN(), but Max([0.5, math.NaN()]) produces 0.5. Since arrays with same elements but different order produce different results (inconsistent), this function does not support float64 arrays.
Max returns the maximum value in the array. For float64 arrays, NaN values are skipped.

#### Example:
```go
gfn.Max([]int16{1, 5, 9, 10}...) // 10
gfn.Max("ab", "cd", "e") // "e"

gfn.Max(1.1, math.NaN(), 2.2) // 2.2
gfn.Max([]float64{math.NaN(), math.NaN(), math.NaN()}...) // NaN
```
[back to top](#gfn)

Expand Down Expand Up @@ -306,11 +309,11 @@ p := gfn.MaxBy(products, func(p Product) int {
[back to top](#gfn)


### gfn.MaxFloat64
### gfn.MaxFloat64 (Deprecated)
```go
func MaxFloat64(array ...float64) float64
```
MaxFloat64 returns the maximum value in the array. NaN values are skipped.
Deprecated: MaxFloat64 returns the maximum value in the array. Use Max instead.

#### Example:
```go
Expand Down Expand Up @@ -361,14 +364,17 @@ gfn.MeanBy(products, func(p Product) float64 {

### gfn.Min
```go
func Min[T Int | Uint | ~float32 | ~string](array ...T) T
func Min[T Int | Uint | Float | ~string](array ...T) T
```
Min returns the minimum value in the array. For float64 arrays, please use MinFloat64. More details in Max.
Min returns the minimum value in the array. For float64 arrays, NaN values are skipped.

#### Example:
```go
gfn.Min(1.1, 2.2, 3.3) // 1.1
gfn.Min([]int16{1, 5, 9, 10}...) // 1

gfn.Min(1, -1, 10) // -1
gfn.Min([]float64{1.1, math.Inf(-1), math.NaN()}...) // math.Inf(-1)
```
[back to top](#gfn)

Expand Down Expand Up @@ -397,11 +403,11 @@ p := gfn.MinBy(products, func(p Product) int {
[back to top](#gfn)


### gfn.MinFloat64
### gfn.MinFloat64 (Deprecated)
```go
func MinFloat64(array ...float64) float64
```
MinFloat64 returns the minimum value in the array. NaN values are skipped.
Deprecated: MinFloat64 returns the minimum value in the array. Use Min instead.

#### Example:
```go
Expand All @@ -413,13 +419,16 @@ gfn.MinFloat64([]float64{1.1, math.Inf(-1), math.NaN()}...) // math.Inf(-1)

### gfn.MinMax
```go
func MinMax[T Int | Uint | ~float32 | ~string](array ...T) (T, T)
func MinMax[T Int | Uint | Float | ~string](array ...T) (T, T)
```
MinMax returns the minimum and maximum value in the array. For float64 arrays, please use MinMaxFloat64.

#### Example:
```go
gfn.MinMax(1, 5, 9, 10) // 1, 10

gfn.MinMax(math.NaN(), 1.85, 2.2) // 1.85, 2.2
gfn.MinMax(math.NaN(), math.NaN(), math.NaN()) // NaN, NaN
```
[back to top](#gfn)

Expand Down Expand Up @@ -450,11 +459,11 @@ gfn.MinMaxBy(products, func(p Product) int {
[back to top](#gfn)


### gfn.MinMaxFloat64
### gfn.MinMaxFloat64 (Deprecated)
```go
func MinMaxFloat64(array ...float64) (float64, float64)
```
MinMaxFloat64 returns the minimum and maximum value in the array. NaN values are skipped.
Deprecated: MinMaxFloat64 returns the minimum and maximum value in the array. Use MinMax instead.

#### Example:
```go
Expand Down
106 changes: 39 additions & 67 deletions math.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
package gfn

import (
"math"
)

/* @example Max
gfn.Max([]int16{1, 5, 9, 10}...) // 10
gfn.Max("ab", "cd", "e") // "e"
gfn.Max(1.1, math.NaN(), 2.2) // 2.2
gfn.Max([]float64{math.NaN(), math.NaN(), math.NaN()}...) // NaN
*/

// Max returns the maximum value in the array. For float64 arrays, please use MaxFloat64.
// NaN value in float64 arrays is not comparable to other values.
// Which means Max([math.NaN(), 0.5]) produces math.NaN(), but Max([0.5, math.NaN()]) produces 0.5.
// Since arrays with same elements but different order produce different results (inconsistent),
// this function does not support float64 arrays.
func Max[T Int | Uint | ~float32 | ~string](array ...T) T {
// Max returns the maximum value in the array. For float64 arrays, NaN values are skipped.
func Max[T Int | Uint | Float | ~string](array ...T) T {
if len(array) == 0 {
panic("array is empty")
}

res := array[0]
for _, v := range array {
if v > res {
if isNaN(v) {
continue
}
if isNaN(res) || v > res {
res = v
}
}
return res
}

// isNaN reports whether input is an IEEE 754 "not-a-number" value.
func isNaN[T Int | Uint | Float | ~string](x T) bool {
// IEEE 754 says that only NaNs satisfy x != x.
return x != x
}

/* @example MaxBy
type Product struct {
name string
Expand Down Expand Up @@ -66,39 +70,31 @@ gfn.MaxFloat64(1.1, math.NaN(), 2.2) // 2.2
gfn.MaxFloat64([]float64{math.NaN(), math.NaN(), math.NaN()}...) // NaN
*/

// MaxFloat64 returns the maximum value in the array. NaN values are skipped.
// Deprecated: MaxFloat64 returns the maximum value in the array. Use Max instead.

Check warning on line 73 in math.go

View workflow job for this annotation

GitHub Actions / analysis

comment on exported function MaxFloat64 should be of the form "MaxFloat64 ..."
func MaxFloat64(array ...float64) float64 {
if len(array) == 0 {
panic("array is empty")
}

res := array[0]
for _, v := range array {
if math.IsNaN(v) {
continue
}
if math.IsNaN(res) || v > res {
res = v
}
}
return res
return Max(array...)
}

/* @example Min
gfn.Min(1.1, 2.2, 3.3) // 1.1
gfn.Min([]int16{1, 5, 9, 10}...) // 1
gfn.Min(1, -1, 10) // -1
gfn.Min([]float64{1.1, math.Inf(-1), math.NaN()}...) // math.Inf(-1)
*/

// Min returns the minimum value in the array. For float64 arrays, please use MinFloat64.
// More details in Max.
func Min[T Int | Uint | ~float32 | ~string](array ...T) T {
// Min returns the minimum value in the array. For float64 arrays, NaN values are skipped.
func Min[T Int | Uint | Float | ~string](array ...T) T {
if len(array) == 0 {
panic("array is empty")
}

res := array[0]
for _, v := range array {
if v < res {
if isNaN(v) {
continue
}
if isNaN(res) || v < res {
res = v
}
}
Expand All @@ -110,22 +106,9 @@ gfn.MinFloat64(1, -1, 10) // -1
gfn.MinFloat64([]float64{1.1, math.Inf(-1), math.NaN()}...) // math.Inf(-1)
*/

// MinFloat64 returns the minimum value in the array. NaN values are skipped.
// Deprecated: MinFloat64 returns the minimum value in the array. Use Min instead.

Check warning on line 109 in math.go

View workflow job for this annotation

GitHub Actions / analysis

comment on exported function MinFloat64 should be of the form "MinFloat64 ..."
func MinFloat64(array ...float64) float64 {
if len(array) == 0 {
panic("array is empty")
}

res := array[0]
for _, v := range array {
if math.IsNaN(v) {
continue
}
if math.IsNaN(res) || v < res {
res = v
}
}
return res
return Min(array...)
}

/* @example MinBy
Expand Down Expand Up @@ -282,21 +265,27 @@ func MeanBy[T any, U Int | Uint | Float](array []T, fn func(T) U) float64 {

/* @example MinMax
gfn.MinMax(1, 5, 9, 10) // 1, 10
gfn.MinMax(math.NaN(), 1.85, 2.2) // 1.85, 2.2
gfn.MinMax(math.NaN(), math.NaN(), math.NaN()) // NaN, NaN
*/

// MinMax returns the minimum and maximum value in the array. For float64 arrays, please use MinMaxFloat64.
func MinMax[T Int | Uint | ~float32 | ~string](array ...T) (T, T) {
func MinMax[T Int | Uint | Float | ~string](array ...T) (T, T) {
if len(array) == 0 {
panic("array is empty")
}

minimum := array[0]
maximum := array[0]
for _, v := range array {
if v < minimum {
if isNaN(v) {
continue
}
if isNaN(minimum) || v < minimum {
minimum = v
}
if v > maximum {
if isNaN(maximum) || v > maximum {
maximum = v
}
}
Expand All @@ -308,26 +297,9 @@ gfn.MinMaxFloat64(math.NaN(), 1.85, 2.2) // 1.85, 2.2
gfn.MinMaxFloat64(math.NaN(), math.NaN(), math.NaN()) // NaN, NaN
*/

// MinMaxFloat64 returns the minimum and maximum value in the array. NaN values are skipped.
// Deprecated: MinMaxFloat64 returns the minimum and maximum value in the array. Use MinMax instead.

Check warning on line 300 in math.go

View workflow job for this annotation

GitHub Actions / analysis

comment on exported function MinMaxFloat64 should be of the form "MinMaxFloat64 ..."
func MinMaxFloat64(array ...float64) (float64, float64) {
if len(array) == 0 {
panic("array is empty")
}

minimum := array[0]
maximum := array[0]
for _, v := range array {
if math.IsNaN(v) {
continue
}
if math.IsNaN(minimum) || v < minimum {
minimum = v
}
if math.IsNaN(maximum) || v > maximum {
maximum = v
}
}
return minimum, maximum
return MinMax(array...)
}

/* @example MinMaxBy
Expand Down
39 changes: 39 additions & 0 deletions math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ func TestMax(t *testing.T) {
type MyInt int
AssertEqual(t, MyInt(3), Max([]MyInt{1, 2, 3}...), "MyInt")

AssertEqual(t, 2.2, Max(math.NaN(), 1, 2.2))
AssertEqual(t, 2.8, Max(1, -1, math.NaN(), 1, 2.8))
AssertEqual(t, math.Inf(1), Max(1, -1, math.NaN(), 1, math.Inf(1)))
AssertEqual(t, math.Inf(1), Max(1, -1, 1, math.Inf(1)))
AssertEqual(t, 1.9, Max(1.9, -1., 1.))
AssertTrue(t, math.IsNaN(Max(math.NaN(), math.NaN(), math.NaN())))

// check empty array
AssertPanics(t, func() {
Max([]int{}...)
Expand Down Expand Up @@ -105,6 +112,14 @@ func TestMin(t *testing.T) {
type MyInt int
AssertEqual(t, MyInt(1), Min([]MyInt{1, 2, 3}...), "MyInt")

// float64 with NaN
AssertEqual(t, 1.85, Min(math.NaN(), 1.85, 2.2))
AssertEqual(t, -1, Min(1, -1, math.NaN(), 1, 2.8))
AssertEqual(t, math.Inf(-1), Min(1, -1, math.NaN(), 1, math.Inf(-1)))
AssertEqual(t, -1, Min(1, -1, 1, math.Inf(1)))
AssertEqual(t, -1, Min(1.9, -1., 1.))
AssertTrue(t, math.IsNaN(Min(math.NaN(), math.NaN(), math.NaN())))

// check empty array
AssertPanics(t, func() {
Min([]int{}...)
Expand Down Expand Up @@ -378,6 +393,30 @@ func TestMinMax(t *testing.T) {
AssertEqual(t, 99999, maxVal)
AssertEqual(t, 0, minVal)
}

// check float64 with NaN values
{
var minVal, maxVal float64
minVal, maxVal = MinMax(math.NaN(), 1.85, 2.2)
AssertEqual(t, 1.85, minVal)
AssertEqual(t, 2.2, maxVal)

minVal, maxVal = MinMax(1, -1, math.NaN(), 1, 2.8)
AssertEqual(t, -1, minVal)
AssertEqual(t, 2.8, maxVal)

minVal, maxVal = MinMax(1, -1, math.NaN(), 1, math.Inf(-1))
AssertEqual(t, math.Inf(-1), minVal)
AssertEqual(t, 1, maxVal)

minVal, maxVal = MinMax(1, -1, 1, math.Inf(1))
AssertEqual(t, -1, minVal)
AssertEqual(t, math.Inf(1), maxVal)

minVal, maxVal = MinMax(math.NaN(), math.NaN(), math.NaN())
AssertTrue(t, math.IsNaN(minVal))
AssertTrue(t, math.IsNaN(maxVal))
}
}

func TestMinMaxFloat64(t *testing.T) {
Expand Down

0 comments on commit 8e652f5

Please sign in to comment.