Skip to content

Commit cf27403

Browse files
hr-98lafriks
andauthored
Round language stats percentage using largest remainder (#22026)
Fix #22023 I've changed how the percentages for the language statistics are rounded because they did not always add up to 100% Now it's done with the largest remainder method, which makes sure that total is 100% Co-authored-by: Lauris BH <[email protected]>
1 parent 0a85537 commit cf27403

File tree

1 file changed

+36
-4
lines changed

1 file changed

+36
-4
lines changed

models/repo/language_stats.go

+36-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package repo
66
import (
77
"context"
88
"math"
9+
"sort"
910
"strings"
1011

1112
"code.gitea.io/gitea/models/db"
@@ -43,29 +44,60 @@ func (stats LanguageStatList) LoadAttributes() {
4344

4445
func (stats LanguageStatList) getLanguagePercentages() map[string]float32 {
4546
langPerc := make(map[string]float32)
46-
var otherPerc float32 = 100
47+
var otherPerc float32
4748
var total int64
4849

4950
for _, stat := range stats {
5051
total += stat.Size
5152
}
5253
if total > 0 {
5354
for _, stat := range stats {
54-
perc := float32(math.Round(float64(stat.Size)/float64(total)*1000) / 10)
55+
perc := float32(float64(stat.Size) / float64(total) * 100)
5556
if perc <= 0.1 {
57+
otherPerc += perc
5658
continue
5759
}
58-
otherPerc -= perc
5960
langPerc[stat.Language] = perc
6061
}
61-
otherPerc = float32(math.Round(float64(otherPerc)*10) / 10)
6262
}
6363
if otherPerc > 0 {
6464
langPerc["other"] = otherPerc
6565
}
66+
roundByLargestRemainder(langPerc, 100)
6667
return langPerc
6768
}
6869

70+
// Rounds to 1 decimal point, target should be the expected sum of percs
71+
func roundByLargestRemainder(percs map[string]float32, target float32) {
72+
leftToDistribute := int(target * 10)
73+
74+
keys := make([]string, 0, len(percs))
75+
76+
for k, v := range percs {
77+
percs[k] = v * 10
78+
floored := math.Floor(float64(percs[k]))
79+
leftToDistribute -= int(floored)
80+
keys = append(keys, k)
81+
}
82+
83+
// Sort the keys by the largest remainder
84+
sort.SliceStable(keys, func(i, j int) bool {
85+
_, remainderI := math.Modf(float64(percs[keys[i]]))
86+
_, remainderJ := math.Modf(float64(percs[keys[j]]))
87+
return remainderI > remainderJ
88+
})
89+
90+
// Increment the values in order of largest remainder
91+
for _, k := range keys {
92+
percs[k] = float32(math.Floor(float64(percs[k])))
93+
if leftToDistribute > 0 {
94+
percs[k]++
95+
leftToDistribute--
96+
}
97+
percs[k] /= 10
98+
}
99+
}
100+
69101
// GetLanguageStats returns the language statistics for a repository
70102
func GetLanguageStats(ctx context.Context, repo *Repository) (LanguageStatList, error) {
71103
stats := make(LanguageStatList, 0, 6)

0 commit comments

Comments
 (0)