view pkg/common/round.go @ 4365:e739a4806d7c

rounding to full days: Fixed typos. Make golint happy with the comments. Unexport local type. Simplify and tightend code.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 09 Sep 2019 18:07:10 +0200
parents 97312d7954ba
children 6a985796f401
line wrap: on
line source

// This is Free Software under GNU Affero General Public License v >= 3.0
// without warranty, see README.md and license for details.
//
// SPDX-License-Identifier: AGPL-3.0-or-later
// License-Filename: LICENSES/AGPL-3.0.txt
//
// Copyright (C) 2018 by via donau
//   – Österreichische Wasserstraßen-Gesellschaft mbH
// Software engineering by Intevation GmbH
//
// Author(s):
//  * Sascha Wilde <wilde@sha-bang.de>

package common

import (
	"math"
	"sort"
	"time"
)

// SumPreservingRound rounds the values of arr preserving the sum.
func SumPreservingRound(arr []float64) []int {

	type rest struct {
		key  int
		rest float64
	}

	var (
		result = make([]int, len(arr))
		rests  = make([]rest, len(arr))
		sum    float64
		newSum int
	)

	// floor all values
	for i, v := range arr {
		sum += v
		result[i] = int(v)
		newSum += int(v)
		rests[i] = rest{key: i, rest: v - float64(result[i])}
	}

	// spread delta over values with highest rest
	sort.Slice(rests, func(i, j int) bool {
		return rests[i].rest > rests[j].rest
	})

	// find the difference in sums
	delta := int(math.Round(sum)) - newSum
	for _, v := range rests {
		if delta <= 0 {
			break
		}
		result[v.key]++
		delta--
	}

	return result
}

// RoundToFullDays rounds durations to full days.
func RoundToFullDays(durations []time.Duration) []int {
	days := make([]float64, len(durations))
	for i, v := range durations {
		days[i] = v.Hours() / 24
	}
	return SumPreservingRound(days)
}