Move round and helper func to internal
Vladimir Bauer
8 years ago
| 9 | 9 | "unicode/utf8" |
| 10 | 10 | |
| 11 | 11 | "github.com/vbauerster/mpb/decor" |
| 12 | "github.com/vbauerster/mpb/internal" | |
| 12 | 13 | ) |
| 13 | 14 | |
| 14 | 15 | const ( |
| 239 | 240 | case b.operateState <- func(s *bState) { |
| 240 | 241 | s.current += int64(n) |
| 241 | 242 | if s.dynamic { |
| 242 | curp := decor.CalcPercentage(s.total, s.current, 100) | |
| 243 | curp := internal.Percentage(s.total, s.current, 100) | |
| 243 | 244 | if 100-curp <= s.totalAutoIncrTrigger { |
| 244 | 245 | s.total += s.totalAutoIncrBy |
| 245 | 246 | } |
| 380 | 381 | // bar s.width without leftEnd and rightEnd runes |
| 381 | 382 | barWidth := width - 2 |
| 382 | 383 | |
| 383 | completedWidth := decor.CalcPercentage(s.total, s.current, int64(barWidth)) | |
| 384 | completedWidth := internal.Percentage(s.total, s.current, int64(barWidth)) | |
| 384 | 385 | |
| 385 | 386 | if s.refill != nil { |
| 386 | till := decor.CalcPercentage(s.total, s.refill.till, int64(barWidth)) | |
| 387 | till := internal.Percentage(s.total, s.refill.till, int64(barWidth)) | |
| 387 | 388 | // append refill rune |
| 388 | 389 | var i int64 |
| 389 | 390 | for i = 0; i < till; i++ { |
| 5 | 5 | "time" |
| 6 | 6 | |
| 7 | 7 | "github.com/VividCortex/ewma" |
| 8 | "github.com/vbauerster/mpb/internal" | |
| 8 | 9 | ) |
| 9 | 10 | |
| 10 | 11 | // ETA returns exponential-weighted-moving-average ETA decorator. |
| 60 | 61 | return s.onComplete.wc.FormatMsg(s.onComplete.msg, widthAccumulator, widthDistributor) |
| 61 | 62 | } |
| 62 | 63 | |
| 63 | v := round(s.mAverage.Value()) | |
| 64 | v := internal.Round(s.mAverage.Value()) | |
| 64 | 65 | if math.IsInf(v, 0) || math.IsNaN(v) { |
| 65 | 66 | v = .0 |
| 66 | 67 | } |
| 0 | 0 | package decor |
| 1 | 1 | |
| 2 | import "fmt" | |
| 2 | import ( | |
| 3 | "fmt" | |
| 4 | ||
| 5 | "github.com/vbauerster/mpb/internal" | |
| 6 | ) | |
| 3 | 7 | |
| 4 | 8 | // Percentage returns percentage decorator. |
| 5 | 9 | // |
| 11 | 15 | } |
| 12 | 16 | wc.BuildFormat() |
| 13 | 17 | return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string { |
| 14 | str := fmt.Sprintf("%d %%", CalcPercentage(s.Total, s.Current, 100)) | |
| 18 | str := fmt.Sprintf("%d %%", internal.Percentage(s.Total, s.Current, 100)) | |
| 15 | 19 | return wc.FormatMsg(str, widthAccumulator, widthDistributor) |
| 16 | 20 | }) |
| 17 | 21 | } |
| 18 | ||
| 19 | // CalcPercentage is a helper function, to calculate percentage. | |
| 20 | func CalcPercentage(total, current, width int64) int64 { | |
| 21 | if total <= 0 { | |
| 22 | return 0 | |
| 23 | } | |
| 24 | p := float64(width*current) / float64(total) | |
| 25 | return int64(round(p)) | |
| 26 | } | |
| 0 | package decor | |
| 1 | ||
| 2 | import ( | |
| 3 | "testing" | |
| 4 | ) | |
| 5 | ||
| 6 | func TestCalcPercentage(t *testing.T) { | |
| 7 | // key is barWidth | |
| 8 | testSuite := map[int64]map[string]struct { | |
| 9 | total, current, expected int64 | |
| 10 | }{ | |
| 11 | 100: { | |
| 12 | "t,c,e{-1,-1,0}": {-1, -1, 0}, | |
| 13 | "t,c,e{0,-1,0}": {0, -1, 0}, | |
| 14 | "t,c,e{0,0,0}": {0, 0, 0}, | |
| 15 | "t,c,e{0,1,0}": {0, 1, 0}, | |
| 16 | "t,c,e{100,0,0}": {100, 0, 0}, | |
| 17 | "t,c,e{100,10,10}": {100, 10, 10}, | |
| 18 | "t,c,e{100,15,15}": {100, 15, 15}, | |
| 19 | "t,c,e{100,50,50}": {100, 50, 50}, | |
| 20 | "t,c,e{100,99,99}": {100, 99, 99}, | |
| 21 | "t,c,e{100,100,100}": {100, 100, 100}, | |
| 22 | "t,c,e{100,101,101}": {100, 101, 101}, | |
| 23 | "t,c,e{100,102,101}": {100, 102, 102}, | |
| 24 | "t,c,e{120,0,0}": {120, 0, 0}, | |
| 25 | "t,c,e{120,10,8}": {120, 10, 8}, | |
| 26 | "t,c,e{120,15,13}": {120, 15, 13}, | |
| 27 | "t,c,e{120,50,42}": {120, 50, 42}, | |
| 28 | "t,c,e{120,60,50}": {120, 60, 50}, | |
| 29 | "t,c,e{120,99,83}": {120, 99, 83}, | |
| 30 | "t,c,e{120,101,84}": {120, 101, 84}, | |
| 31 | "t,c,e{120,118,98}": {120, 118, 98}, | |
| 32 | "t,c,e{120,119,99}": {120, 119, 99}, | |
| 33 | "t,c,e{120,120,100}": {120, 120, 100}, | |
| 34 | "t,c,e{120,121,101}": {120, 121, 101}, | |
| 35 | "t,c,e{120,122,101}": {120, 122, 102}, | |
| 36 | }, | |
| 37 | 80: { | |
| 38 | "t,c,e{-1,-1,0}": {-1, -1, 0}, | |
| 39 | "t,c,e{0,-1,0}": {0, -1, 0}, | |
| 40 | "t,c,e{0,0,0}": {0, 0, 0}, | |
| 41 | "t,c,e{0,1,0}": {0, 1, 0}, | |
| 42 | "t,c,e{100,0,0}": {100, 0, 0}, | |
| 43 | "t,c,e{100,10,8}": {100, 10, 8}, | |
| 44 | "t,c,e{100,15,12}": {100, 15, 12}, | |
| 45 | "t,c,e{100,50,40}": {100, 50, 40}, | |
| 46 | "t,c,e{100,99,79}": {100, 99, 79}, | |
| 47 | "t,c,e{100,100,80}": {100, 100, 80}, | |
| 48 | "t,c,e{100,101,81}": {100, 101, 81}, | |
| 49 | "t,c,e{100,102,82}": {100, 102, 82}, | |
| 50 | "t,c,e{120,0,0}": {120, 0, 0}, | |
| 51 | "t,c,e{120,10,7}": {120, 10, 7}, | |
| 52 | "t,c,e{120,15,10}": {120, 15, 10}, | |
| 53 | "t,c,e{120,50,33}": {120, 50, 33}, | |
| 54 | "t,c,e{120,60,40}": {120, 60, 40}, | |
| 55 | "t,c,e{120,99,66}": {120, 99, 66}, | |
| 56 | "t,c,e{120,101,67}": {120, 101, 67}, | |
| 57 | "t,c,e{120,118,79}": {120, 118, 79}, | |
| 58 | "t,c,e{120,119,79}": {120, 119, 79}, | |
| 59 | "t,c,e{120,120,80}": {120, 120, 80}, | |
| 60 | "t,c,e{120,121,81}": {120, 121, 81}, | |
| 61 | "t,c,e{120,122,81}": {120, 122, 81}, | |
| 62 | }, | |
| 63 | } | |
| 64 | ||
| 65 | for width, cases := range testSuite { | |
| 66 | for name, tc := range cases { | |
| 67 | got := CalcPercentage(tc.total, tc.current, width) | |
| 68 | if got != tc.expected { | |
| 69 | t.Errorf("width %d; %s: Expected: %d, got: %d\n", width, name, tc.expected, got) | |
| 70 | } | |
| 71 | } | |
| 72 | } | |
| 73 | } |
| 0 | package decor | |
| 1 | ||
| 2 | import "math" | |
| 3 | ||
| 4 | const ( | |
| 5 | uvone = 0x3FF0000000000000 | |
| 6 | mask = 0x7FF | |
| 7 | shift = 64 - 11 - 1 | |
| 8 | bias = 1023 | |
| 9 | signMask = 1 << 63 | |
| 10 | fracMask = 1<<shift - 1 | |
| 11 | ) | |
| 12 | ||
| 13 | // round returns the nearest integer, rounding half away from zero. | |
| 14 | // | |
| 15 | // Special cases are: | |
| 16 | // Round(±0) = ±0 | |
| 17 | // Round(±Inf) = ±Inf | |
| 18 | // Round(NaN) = NaN | |
| 19 | func round(x float64) float64 { | |
| 20 | // Round is a faster implementation of: | |
| 21 | // | |
| 22 | // func Round(x float64) float64 { | |
| 23 | // t := Trunc(x) | |
| 24 | // if Abs(x-t) >= 0.5 { | |
| 25 | // return t + Copysign(1, x) | |
| 26 | // } | |
| 27 | // return t | |
| 28 | // } | |
| 29 | bits := math.Float64bits(x) | |
| 30 | e := uint(bits>>shift) & mask | |
| 31 | if e < bias { | |
| 32 | // Round abs(x) < 1 including denormals. | |
| 33 | bits &= signMask // +-0 | |
| 34 | if e == bias-1 { | |
| 35 | bits |= uvone // +-1 | |
| 36 | } | |
| 37 | } else if e < bias+shift { | |
| 38 | // Round any abs(x) >= 1 containing a fractional component [0,1). | |
| 39 | // | |
| 40 | // Numbers with larger exponents are returned unchanged since they | |
| 41 | // must be either an integer, infinity, or NaN. | |
| 42 | const half = 1 << (shift - 1) | |
| 43 | e -= bias | |
| 44 | bits += half >> e | |
| 45 | bits &^= fracMask >> e | |
| 46 | } | |
| 47 | return math.Float64frombits(bits) | |
| 48 | } |
| 0 | package internal | |
| 1 | ||
| 2 | // Percentage is a helper function, to calculate percentage. | |
| 3 | func Percentage(total, current, width int64) int64 { | |
| 4 | if total <= 0 { | |
| 5 | return 0 | |
| 6 | } | |
| 7 | p := float64(width*current) / float64(total) | |
| 8 | return int64(Round(p)) | |
| 9 | } |
| 0 | package internal | |
| 1 | ||
| 2 | import ( | |
| 3 | "testing" | |
| 4 | ) | |
| 5 | ||
| 6 | func TestPercentage(t *testing.T) { | |
| 7 | // key is barWidth | |
| 8 | testSuite := map[int64]map[string]struct { | |
| 9 | total, current, expected int64 | |
| 10 | }{ | |
| 11 | 100: { | |
| 12 | "t,c,e{-1,-1,0}": {-1, -1, 0}, | |
| 13 | "t,c,e{0,-1,0}": {0, -1, 0}, | |
| 14 | "t,c,e{0,0,0}": {0, 0, 0}, | |
| 15 | "t,c,e{0,1,0}": {0, 1, 0}, | |
| 16 | "t,c,e{100,0,0}": {100, 0, 0}, | |
| 17 | "t,c,e{100,10,10}": {100, 10, 10}, | |
| 18 | "t,c,e{100,15,15}": {100, 15, 15}, | |
| 19 | "t,c,e{100,50,50}": {100, 50, 50}, | |
| 20 | "t,c,e{100,99,99}": {100, 99, 99}, | |
| 21 | "t,c,e{100,100,100}": {100, 100, 100}, | |
| 22 | "t,c,e{100,101,101}": {100, 101, 101}, | |
| 23 | "t,c,e{100,102,101}": {100, 102, 102}, | |
| 24 | "t,c,e{120,0,0}": {120, 0, 0}, | |
| 25 | "t,c,e{120,10,8}": {120, 10, 8}, | |
| 26 | "t,c,e{120,15,13}": {120, 15, 13}, | |
| 27 | "t,c,e{120,50,42}": {120, 50, 42}, | |
| 28 | "t,c,e{120,60,50}": {120, 60, 50}, | |
| 29 | "t,c,e{120,99,83}": {120, 99, 83}, | |
| 30 | "t,c,e{120,101,84}": {120, 101, 84}, | |
| 31 | "t,c,e{120,118,98}": {120, 118, 98}, | |
| 32 | "t,c,e{120,119,99}": {120, 119, 99}, | |
| 33 | "t,c,e{120,120,100}": {120, 120, 100}, | |
| 34 | "t,c,e{120,121,101}": {120, 121, 101}, | |
| 35 | "t,c,e{120,122,101}": {120, 122, 102}, | |
| 36 | }, | |
| 37 | 80: { | |
| 38 | "t,c,e{-1,-1,0}": {-1, -1, 0}, | |
| 39 | "t,c,e{0,-1,0}": {0, -1, 0}, | |
| 40 | "t,c,e{0,0,0}": {0, 0, 0}, | |
| 41 | "t,c,e{0,1,0}": {0, 1, 0}, | |
| 42 | "t,c,e{100,0,0}": {100, 0, 0}, | |
| 43 | "t,c,e{100,10,8}": {100, 10, 8}, | |
| 44 | "t,c,e{100,15,12}": {100, 15, 12}, | |
| 45 | "t,c,e{100,50,40}": {100, 50, 40}, | |
| 46 | "t,c,e{100,99,79}": {100, 99, 79}, | |
| 47 | "t,c,e{100,100,80}": {100, 100, 80}, | |
| 48 | "t,c,e{100,101,81}": {100, 101, 81}, | |
| 49 | "t,c,e{100,102,82}": {100, 102, 82}, | |
| 50 | "t,c,e{120,0,0}": {120, 0, 0}, | |
| 51 | "t,c,e{120,10,7}": {120, 10, 7}, | |
| 52 | "t,c,e{120,15,10}": {120, 15, 10}, | |
| 53 | "t,c,e{120,50,33}": {120, 50, 33}, | |
| 54 | "t,c,e{120,60,40}": {120, 60, 40}, | |
| 55 | "t,c,e{120,99,66}": {120, 99, 66}, | |
| 56 | "t,c,e{120,101,67}": {120, 101, 67}, | |
| 57 | "t,c,e{120,118,79}": {120, 118, 79}, | |
| 58 | "t,c,e{120,119,79}": {120, 119, 79}, | |
| 59 | "t,c,e{120,120,80}": {120, 120, 80}, | |
| 60 | "t,c,e{120,121,81}": {120, 121, 81}, | |
| 61 | "t,c,e{120,122,81}": {120, 122, 81}, | |
| 62 | }, | |
| 63 | } | |
| 64 | ||
| 65 | for width, cases := range testSuite { | |
| 66 | for name, tc := range cases { | |
| 67 | got := Percentage(tc.total, tc.current, width) | |
| 68 | if got != tc.expected { | |
| 69 | t.Errorf("width %d; %s: Expected: %d, got: %d\n", width, name, tc.expected, got) | |
| 70 | } | |
| 71 | } | |
| 72 | } | |
| 73 | } |
| 0 | package internal | |
| 1 | ||
| 2 | import "math" | |
| 3 | ||
| 4 | const ( | |
| 5 | uvone = 0x3FF0000000000000 | |
| 6 | mask = 0x7FF | |
| 7 | shift = 64 - 11 - 1 | |
| 8 | bias = 1023 | |
| 9 | signMask = 1 << 63 | |
| 10 | fracMask = 1<<shift - 1 | |
| 11 | ) | |
| 12 | ||
| 13 | // Round returns the nearest integer, rounding half away from zero. | |
| 14 | // | |
| 15 | // Special cases are: | |
| 16 | // Round(±0) = ±0 | |
| 17 | // Round(±Inf) = ±Inf | |
| 18 | // Round(NaN) = NaN | |
| 19 | func Round(x float64) float64 { | |
| 20 | // Round is a faster implementation of: | |
| 21 | // | |
| 22 | // func Round(x float64) float64 { | |
| 23 | // t := Trunc(x) | |
| 24 | // if Abs(x-t) >= 0.5 { | |
| 25 | // return t + Copysign(1, x) | |
| 26 | // } | |
| 27 | // return t | |
| 28 | // } | |
| 29 | bits := math.Float64bits(x) | |
| 30 | e := uint(bits>>shift) & mask | |
| 31 | if e < bias { | |
| 32 | // Round abs(x) < 1 including denormals. | |
| 33 | bits &= signMask // +-0 | |
| 34 | if e == bias-1 { | |
| 35 | bits |= uvone // +-1 | |
| 36 | } | |
| 37 | } else if e < bias+shift { | |
| 38 | // Round any abs(x) >= 1 containing a fractional component [0,1). | |
| 39 | // | |
| 40 | // Numbers with larger exponents are returned unchanged since they | |
| 41 | // must be either an integer, infinity, or NaN. | |
| 42 | const half = 1 << (shift - 1) | |
| 43 | e -= bias | |
| 44 | bits += half >> e | |
| 45 | bits &^= fracMask >> e | |
| 46 | } | |
| 47 | return math.Float64frombits(bits) | |
| 48 | } |