blob: c4f802a6f6bc225b0143af968bd545681d205eb1 [file] [log] [blame]
// Copyright 2018 The CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package list
import (
"fmt"
"github.com/cockroachdb/apd/v2"
"cuelang.org/go/internal"
)
// Avg returns the average value of a non empty list xs.
func Avg(xs []*internal.Decimal) (*internal.Decimal, error) {
if 0 == len(xs) {
return nil, fmt.Errorf("empty list")
}
s := apd.New(0, 0)
for _, x := range xs {
_, err := internal.BaseContext.Add(s, x, s)
if err != nil {
return nil, err
}
}
var d apd.Decimal
l := apd.New(int64(len(xs)), 0)
_, err := internal.BaseContext.Quo(&d, s, l)
if err != nil {
return nil, err
}
return &d, nil
}
// Max returns the maximum value of a non empty list xs.
func Max(xs []*internal.Decimal) (*internal.Decimal, error) {
if 0 == len(xs) {
return nil, fmt.Errorf("empty list")
}
max := xs[0]
for _, x := range xs[1:] {
if -1 == max.Cmp(x) {
max = x
}
}
return max, nil
}
// Min returns the minimum value of a non empty list xs.
func Min(xs []*internal.Decimal) (*internal.Decimal, error) {
if 0 == len(xs) {
return nil, fmt.Errorf("empty list")
}
min := xs[0]
for _, x := range xs[1:] {
if +1 == min.Cmp(x) {
min = x
}
}
return min, nil
}
// Product returns the product of a non empty list xs.
func Product(xs []*internal.Decimal) (*internal.Decimal, error) {
d := apd.New(1, 0)
for _, x := range xs {
_, err := internal.BaseContext.Mul(d, x, d)
if err != nil {
return nil, err
}
}
return d, nil
}
// Range generates a list of numbers using a start value, a limit value, and a
// step value.
//
// For instance:
//
// Range(0, 5, 2)
//
// results in
//
// [0, 2, 4]
//
func Range(start, limit, step *internal.Decimal) ([]*internal.Decimal, error) {
if step.IsZero() {
return nil, fmt.Errorf("step must be non zero")
}
if !step.Negative && +1 == start.Cmp(limit) {
return nil, fmt.Errorf("end must be greater than start when step is positive")
}
if step.Negative && -1 == start.Cmp(limit) {
return nil, fmt.Errorf("end must be less than start when step is negative")
}
var vals []*internal.Decimal
num := start
for {
if !step.Negative && -1 != num.Cmp(limit) {
break
}
if step.Negative && +1 != num.Cmp(limit) {
break
}
vals = append(vals, num)
d := apd.New(0, 0)
_, err := internal.BaseContext.Add(d, step, num)
if err != nil {
return nil, err
}
num = d
}
return vals, nil
}
// Sum returns the sum of a list non empty xs.
func Sum(xs []*internal.Decimal) (*internal.Decimal, error) {
d := apd.New(0, 0)
for _, x := range xs {
_, err := internal.BaseContext.Add(d, x, d)
if err != nil {
return nil, err
}
}
return d, nil
}