diff --git a/bar.go b/bar.go index 1996dd2..2dd5c32 100644 --- a/bar.go +++ b/bar.go @@ -10,6 +10,7 @@ "unicode/utf8" "github.com/vbauerster/mpb/decor" + "github.com/vbauerster/mpb/internal" ) const ( @@ -240,7 +241,7 @@ case b.operateState <- func(s *bState) { s.current += int64(n) if s.dynamic { - curp := decor.CalcPercentage(s.total, s.current, 100) + curp := internal.Percentage(s.total, s.current, 100) if 100-curp <= s.totalAutoIncrTrigger { s.total += s.totalAutoIncrBy } @@ -381,10 +382,10 @@ // bar s.width without leftEnd and rightEnd runes barWidth := width - 2 - completedWidth := decor.CalcPercentage(s.total, s.current, int64(barWidth)) + completedWidth := internal.Percentage(s.total, s.current, int64(barWidth)) if s.refill != nil { - till := decor.CalcPercentage(s.total, s.refill.till, int64(barWidth)) + till := internal.Percentage(s.total, s.refill.till, int64(barWidth)) // append refill rune var i int64 for i = 0; i < till; i++ { diff --git a/decor/eta.go b/decor/eta.go index 116d183..89144f9 100644 --- a/decor/eta.go +++ b/decor/eta.go @@ -6,6 +6,7 @@ "time" "github.com/VividCortex/ewma" + "github.com/vbauerster/mpb/internal" ) // ETA returns exponential-weighted-moving-average ETA decorator. @@ -61,7 +62,7 @@ return s.onComplete.wc.FormatMsg(s.onComplete.msg, widthAccumulator, widthDistributor) } - v := round(s.mAverage.Value()) + v := internal.Round(s.mAverage.Value()) if math.IsInf(v, 0) || math.IsNaN(v) { v = .0 } diff --git a/decor/percentage.go b/decor/percentage.go index 474826c..442af0b 100644 --- a/decor/percentage.go +++ b/decor/percentage.go @@ -1,6 +1,10 @@ package decor -import "fmt" +import ( + "fmt" + + "github.com/vbauerster/mpb/internal" +) // Percentage returns percentage decorator. // @@ -12,16 +16,7 @@ } wc.BuildFormat() return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string { - str := fmt.Sprintf("%d %%", CalcPercentage(s.Total, s.Current, 100)) + str := fmt.Sprintf("%d %%", internal.Percentage(s.Total, s.Current, 100)) return wc.FormatMsg(str, widthAccumulator, widthDistributor) }) } - -// CalcPercentage is a helper function, to calculate percentage. -func CalcPercentage(total, current, width int64) int64 { - if total <= 0 { - return 0 - } - p := float64(width*current) / float64(total) - return int64(round(p)) -} diff --git a/decor/percentage_test.go b/decor/percentage_test.go deleted file mode 100644 index 1066c0c..0000000 --- a/decor/percentage_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package decor - -import ( - "testing" -) - -func TestCalcPercentage(t *testing.T) { - // key is barWidth - testSuite := map[int64]map[string]struct { - total, current, expected int64 - }{ - 100: { - "t,c,e{-1,-1,0}": {-1, -1, 0}, - "t,c,e{0,-1,0}": {0, -1, 0}, - "t,c,e{0,0,0}": {0, 0, 0}, - "t,c,e{0,1,0}": {0, 1, 0}, - "t,c,e{100,0,0}": {100, 0, 0}, - "t,c,e{100,10,10}": {100, 10, 10}, - "t,c,e{100,15,15}": {100, 15, 15}, - "t,c,e{100,50,50}": {100, 50, 50}, - "t,c,e{100,99,99}": {100, 99, 99}, - "t,c,e{100,100,100}": {100, 100, 100}, - "t,c,e{100,101,101}": {100, 101, 101}, - "t,c,e{100,102,101}": {100, 102, 102}, - "t,c,e{120,0,0}": {120, 0, 0}, - "t,c,e{120,10,8}": {120, 10, 8}, - "t,c,e{120,15,13}": {120, 15, 13}, - "t,c,e{120,50,42}": {120, 50, 42}, - "t,c,e{120,60,50}": {120, 60, 50}, - "t,c,e{120,99,83}": {120, 99, 83}, - "t,c,e{120,101,84}": {120, 101, 84}, - "t,c,e{120,118,98}": {120, 118, 98}, - "t,c,e{120,119,99}": {120, 119, 99}, - "t,c,e{120,120,100}": {120, 120, 100}, - "t,c,e{120,121,101}": {120, 121, 101}, - "t,c,e{120,122,101}": {120, 122, 102}, - }, - 80: { - "t,c,e{-1,-1,0}": {-1, -1, 0}, - "t,c,e{0,-1,0}": {0, -1, 0}, - "t,c,e{0,0,0}": {0, 0, 0}, - "t,c,e{0,1,0}": {0, 1, 0}, - "t,c,e{100,0,0}": {100, 0, 0}, - "t,c,e{100,10,8}": {100, 10, 8}, - "t,c,e{100,15,12}": {100, 15, 12}, - "t,c,e{100,50,40}": {100, 50, 40}, - "t,c,e{100,99,79}": {100, 99, 79}, - "t,c,e{100,100,80}": {100, 100, 80}, - "t,c,e{100,101,81}": {100, 101, 81}, - "t,c,e{100,102,82}": {100, 102, 82}, - "t,c,e{120,0,0}": {120, 0, 0}, - "t,c,e{120,10,7}": {120, 10, 7}, - "t,c,e{120,15,10}": {120, 15, 10}, - "t,c,e{120,50,33}": {120, 50, 33}, - "t,c,e{120,60,40}": {120, 60, 40}, - "t,c,e{120,99,66}": {120, 99, 66}, - "t,c,e{120,101,67}": {120, 101, 67}, - "t,c,e{120,118,79}": {120, 118, 79}, - "t,c,e{120,119,79}": {120, 119, 79}, - "t,c,e{120,120,80}": {120, 120, 80}, - "t,c,e{120,121,81}": {120, 121, 81}, - "t,c,e{120,122,81}": {120, 122, 81}, - }, - } - - for width, cases := range testSuite { - for name, tc := range cases { - got := CalcPercentage(tc.total, tc.current, width) - if got != tc.expected { - t.Errorf("width %d; %s: Expected: %d, got: %d\n", width, name, tc.expected, got) - } - } - } -} diff --git a/decor/round.go b/decor/round.go deleted file mode 100644 index 5ca3b70..0000000 --- a/decor/round.go +++ /dev/null @@ -1,49 +0,0 @@ -package decor - -import "math" - -const ( - uvone = 0x3FF0000000000000 - mask = 0x7FF - shift = 64 - 11 - 1 - bias = 1023 - signMask = 1 << 63 - fracMask = 1<= 0.5 { - // return t + Copysign(1, x) - // } - // return t - // } - bits := math.Float64bits(x) - e := uint(bits>>shift) & mask - if e < bias { - // Round abs(x) < 1 including denormals. - bits &= signMask // +-0 - if e == bias-1 { - bits |= uvone // +-1 - } - } else if e < bias+shift { - // Round any abs(x) >= 1 containing a fractional component [0,1). - // - // Numbers with larger exponents are returned unchanged since they - // must be either an integer, infinity, or NaN. - const half = 1 << (shift - 1) - e -= bias - bits += half >> e - bits &^= fracMask >> e - } - return math.Float64frombits(bits) -} diff --git a/internal/percentage.go b/internal/percentage.go new file mode 100644 index 0000000..3c8defb --- /dev/null +++ b/internal/percentage.go @@ -0,0 +1,10 @@ +package internal + +// Percentage is a helper function, to calculate percentage. +func Percentage(total, current, width int64) int64 { + if total <= 0 { + return 0 + } + p := float64(width*current) / float64(total) + return int64(Round(p)) +} diff --git a/internal/percentage_test.go b/internal/percentage_test.go new file mode 100644 index 0000000..ce5a25e --- /dev/null +++ b/internal/percentage_test.go @@ -0,0 +1,74 @@ +package internal + +import ( + "testing" +) + +func TestPercentage(t *testing.T) { + // key is barWidth + testSuite := map[int64]map[string]struct { + total, current, expected int64 + }{ + 100: { + "t,c,e{-1,-1,0}": {-1, -1, 0}, + "t,c,e{0,-1,0}": {0, -1, 0}, + "t,c,e{0,0,0}": {0, 0, 0}, + "t,c,e{0,1,0}": {0, 1, 0}, + "t,c,e{100,0,0}": {100, 0, 0}, + "t,c,e{100,10,10}": {100, 10, 10}, + "t,c,e{100,15,15}": {100, 15, 15}, + "t,c,e{100,50,50}": {100, 50, 50}, + "t,c,e{100,99,99}": {100, 99, 99}, + "t,c,e{100,100,100}": {100, 100, 100}, + "t,c,e{100,101,101}": {100, 101, 101}, + "t,c,e{100,102,101}": {100, 102, 102}, + "t,c,e{120,0,0}": {120, 0, 0}, + "t,c,e{120,10,8}": {120, 10, 8}, + "t,c,e{120,15,13}": {120, 15, 13}, + "t,c,e{120,50,42}": {120, 50, 42}, + "t,c,e{120,60,50}": {120, 60, 50}, + "t,c,e{120,99,83}": {120, 99, 83}, + "t,c,e{120,101,84}": {120, 101, 84}, + "t,c,e{120,118,98}": {120, 118, 98}, + "t,c,e{120,119,99}": {120, 119, 99}, + "t,c,e{120,120,100}": {120, 120, 100}, + "t,c,e{120,121,101}": {120, 121, 101}, + "t,c,e{120,122,101}": {120, 122, 102}, + }, + 80: { + "t,c,e{-1,-1,0}": {-1, -1, 0}, + "t,c,e{0,-1,0}": {0, -1, 0}, + "t,c,e{0,0,0}": {0, 0, 0}, + "t,c,e{0,1,0}": {0, 1, 0}, + "t,c,e{100,0,0}": {100, 0, 0}, + "t,c,e{100,10,8}": {100, 10, 8}, + "t,c,e{100,15,12}": {100, 15, 12}, + "t,c,e{100,50,40}": {100, 50, 40}, + "t,c,e{100,99,79}": {100, 99, 79}, + "t,c,e{100,100,80}": {100, 100, 80}, + "t,c,e{100,101,81}": {100, 101, 81}, + "t,c,e{100,102,82}": {100, 102, 82}, + "t,c,e{120,0,0}": {120, 0, 0}, + "t,c,e{120,10,7}": {120, 10, 7}, + "t,c,e{120,15,10}": {120, 15, 10}, + "t,c,e{120,50,33}": {120, 50, 33}, + "t,c,e{120,60,40}": {120, 60, 40}, + "t,c,e{120,99,66}": {120, 99, 66}, + "t,c,e{120,101,67}": {120, 101, 67}, + "t,c,e{120,118,79}": {120, 118, 79}, + "t,c,e{120,119,79}": {120, 119, 79}, + "t,c,e{120,120,80}": {120, 120, 80}, + "t,c,e{120,121,81}": {120, 121, 81}, + "t,c,e{120,122,81}": {120, 122, 81}, + }, + } + + for width, cases := range testSuite { + for name, tc := range cases { + got := Percentage(tc.total, tc.current, width) + if got != tc.expected { + t.Errorf("width %d; %s: Expected: %d, got: %d\n", width, name, tc.expected, got) + } + } + } +} diff --git a/internal/round.go b/internal/round.go new file mode 100644 index 0000000..c54a789 --- /dev/null +++ b/internal/round.go @@ -0,0 +1,49 @@ +package internal + +import "math" + +const ( + uvone = 0x3FF0000000000000 + mask = 0x7FF + shift = 64 - 11 - 1 + bias = 1023 + signMask = 1 << 63 + fracMask = 1<= 0.5 { + // return t + Copysign(1, x) + // } + // return t + // } + bits := math.Float64bits(x) + e := uint(bits>>shift) & mask + if e < bias { + // Round abs(x) < 1 including denormals. + bits &= signMask // +-0 + if e == bias-1 { + bits |= uvone // +-1 + } + } else if e < bias+shift { + // Round any abs(x) >= 1 containing a fractional component [0,1). + // + // Numbers with larger exponents are returned unchanged since they + // must be either an integer, infinity, or NaN. + const half = 1 << (shift - 1) + e -= bias + bits += half >> e + bits &^= fracMask >> e + } + return math.Float64frombits(bits) +}