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)
+}