Mercurial > gemma
diff pkg/common/round.go @ 4353:97312d7954ba fa-round-in-backend
FA diagrams: round to full days in back end.
author | Sascha Wilde <wilde@intevation.de> |
---|---|
date | Mon, 09 Sep 2019 15:14:55 +0200 |
parents | |
children | e739a4806d7c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/common/round.go Mon Sep 09 15:14:55 2019 +0200 @@ -0,0 +1,71 @@ +// 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" +) + +type Rest struct { + Key int + Rest float64 +} + +// Simple sum preserving rounding method: +func SumPreservingRound(arr []float64) []int { + var ( + sum float64 + rests []Rest + ) + result := make([]int, len(arr)) + + // floor all values + for i, v := range arr { + sum += v + result[i] = int(v) + rests = append(rests, Rest{Key: i, Rest: v - float64(result[i])}) + } + + // find the difference in summs + var newSum int + for _, v := range result { + newSum += v + } + delta := int(math.Round(sum)) - newSum + + // spread delta over values with highest rest + sort.Slice(rests, func(i, j int) bool { + return rests[i].Rest > rests[j].Rest + }) + for _, v := range rests { + if delta <= 0 { + break + } + result[v.Key]++ + delta-- + } + + return result +} + +// Round anarray of Duratons 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) +}