internal/number: clean up RoundingContext - remove Scale and Precision fields - pass RoundingContext as value (safer) - fixes a bug as a side-effect Change-Id: I248eccae2ad7fa5fe411b0893eaf784e8b10aca7 Reviewed-on: https://go-review.googlesource.com/58570 Run-TryBot: Marcel van Lohuizen <mpvl@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/internal/number/decimal.go b/internal/number/decimal.go index 7c28dc1..443c69e 100644 --- a/internal/number/decimal.go +++ b/internal/number/decimal.go
@@ -292,7 +292,7 @@ // A Converter converts a number into decimals according to the given rounding // criteria. type Converter interface { - Convert(d *Decimal, r *RoundingContext) + Convert(d *Decimal, r RoundingContext) } const ( @@ -302,7 +302,7 @@ // Convert converts the given number to the decimal representation using the // supplied RoundingContext. -func (d *Decimal) Convert(r *RoundingContext, number interface{}) { +func (d *Decimal) Convert(r RoundingContext, number interface{}) { switch f := number.(type) { case Converter: d.clear() @@ -344,7 +344,7 @@ } // ConvertInt converts an integer to decimals. -func (d *Decimal) ConvertInt(r *RoundingContext, signed bool, x uint64) { +func (d *Decimal) ConvertInt(r RoundingContext, signed bool, x uint64) { if r.Increment > 0 { // TODO: if uint64 is too large, fall back to float64 if signed { @@ -364,7 +364,7 @@ } // ConvertFloat converts a floating point number to decimals. -func (d *Decimal) ConvertFloat(r *RoundingContext, x float64, size int) { +func (d *Decimal) ConvertFloat(r RoundingContext, x float64, size int) { d.clear() if math.IsNaN(x) { d.NaN = true @@ -380,11 +380,13 @@ return } // Simple case: decimal notation - if r.Scale > 0 || r.Increment > 0 || r.Precision == 0 { - if int(r.Scale) > len(scales) { - x *= math.Pow(10, float64(r.Scale)) + scale := r.scale() + prec := r.precision() + if scale > 0 || r.Increment > 0 || prec == 0 { + if scale > len(scales) { + x *= math.Pow(10, float64(scale)) } else { - x *= scales[r.Scale] + x *= scales[scale] } if r.Increment > 0 { inc := float64(r.Increment) @@ -395,7 +397,7 @@ x = r.Mode.roundFloat(x) } d.fillIntDigits(uint64(math.Abs(x))) - d.Exp = int32(len(d.Digits)) - r.Scale + d.Exp = int32(len(d.Digits) - scale) return } @@ -407,7 +409,6 @@ // AppendDigits(dst []byte, x float64, base, size, prec int) (digits []byte, exp, accuracy int) // TODO: This only supports the nearest even rounding mode. - prec := int(r.Precision) if prec > 0 { prec-- }
diff --git a/internal/number/decimal_test.go b/internal/number/decimal_test.go index 11d7644..7860459 100644 --- a/internal/number/decimal_test.go +++ b/internal/number/decimal_test.go
@@ -23,13 +23,13 @@ // value NaN, Inf, or -Inf. func mkdec(num string) (d Decimal) { var r RoundingContext - d.Convert(&r, dec(num)) + d.Convert(r, dec(num)) return } type dec string -func (s dec) Convert(d *Decimal, _ *RoundingContext) { +func (s dec) Convert(d *Decimal, _ RoundingContext) { num := string(s) if num[0] == '-' { d.Neg = true @@ -241,14 +241,18 @@ } func TestConvert(t *testing.T) { - scale2 := &RoundingContext{Scale: 2} - scale2away := &RoundingContext{Scale: 2, Mode: AwayFromZero} - inc0_05 := &RoundingContext{Increment: 5, Scale: 2} - inc50 := &RoundingContext{Increment: 50} - prec3 := &RoundingContext{Precision: 3} + scale2 := RoundingContext{} + scale2.SetScale(2) + scale2away := RoundingContext{Mode: AwayFromZero} + scale2away.SetScale(2) + inc0_05 := RoundingContext{Increment: 5} + inc0_05.SetScale(2) + inc50 := RoundingContext{Increment: 50} + prec3 := RoundingContext{} + prec3.SetPrecision(3) testCases := []struct { x interface{} - rc *RoundingContext + rc RoundingContext out string }{ {int8(-34), scale2, "-34"}, @@ -294,7 +298,7 @@ type converter int -func (c converter) Convert(d *Decimal, r *RoundingContext) { +func (c converter) Convert(d *Decimal, r RoundingContext) { d.Digits = append(d.Digits, 1, 0, 0) d.Exp = 3 }
diff --git a/internal/number/format.go b/internal/number/format.go index 9c764dc..744120a 100755 --- a/internal/number/format.go +++ b/internal/number/format.go
@@ -81,12 +81,12 @@ func (f *Formatter) Append(dst []byte, x interface{}) []byte { var d Decimal - r := &f.RoundingContext + r := f.RoundingContext d.Convert(r, x) return f.Render(dst, FormatDigits(&d, r)) } -func FormatDigits(d *Decimal, r *RoundingContext) Digits { +func FormatDigits(d *Decimal, r RoundingContext) Digits { if r.isScientific() { return scientificVisibleDigits(r, d) } @@ -94,7 +94,7 @@ } func (f *Formatter) Format(dst []byte, d *Decimal) []byte { - return f.Render(dst, FormatDigits(d, &f.RoundingContext)) + return f.Render(dst, FormatDigits(d, f.RoundingContext)) } func (f *Formatter) Render(dst []byte, d Digits) []byte { @@ -142,7 +142,7 @@ return result } -func decimalVisibleDigits(r *RoundingContext, d *Decimal) Digits { +func decimalVisibleDigits(r RoundingContext, d *Decimal) Digits { if d.NaN || d.Inf { return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}} } @@ -282,7 +282,7 @@ return appendAffix(dst, f, suffix, neg), savedLen, len(dst) } -func scientificVisibleDigits(r *RoundingContext, d *Decimal) Digits { +func scientificVisibleDigits(r RoundingContext, d *Decimal) Digits { if d.NaN || d.Inf { return Digits{digits: digits{Neg: d.Neg, NaN: d.NaN, Inf: d.Inf}} }
diff --git a/internal/number/format_test.go b/internal/number/format_test.go index c56cbc1..fc7c36d 100755 --- a/internal/number/format_test.go +++ b/internal/number/format_test.go
@@ -453,7 +453,7 @@ buf := make([]byte, 100) t.Run(tc.pattern+"/"+num, func(t *testing.T) { var d Decimal - d.Convert(&f.RoundingContext, dec(num)) + d.Convert(f.RoundingContext, dec(num)) buf = f.Format(buf[:0], &d) if got := string(buf); got != want { t.Errorf("\n got %[1]q (%[1]s)\nwant %[2]q (%[2]s)", got, want) @@ -480,7 +480,7 @@ var f Formatter f.InitDecimal(tc.tag) var d Decimal - d.Convert(&f.RoundingContext, dec(tc.num)) + d.Convert(f.RoundingContext, dec(tc.num)) b := f.Format(nil, &d) if got := string(b); got != tc.want { t.Errorf("got %[1]q (%[1]s); want %[2]q (%[2]s)", got, tc.want) @@ -508,7 +508,7 @@ tc.init(language.English) f.SetScale(2) var d Decimal - d.Convert(&f.RoundingContext, dec(tc.num)) + d.Convert(f.RoundingContext, dec(tc.num)) b := f.Format(nil, &d) if got := string(b); got != tc.want { t.Errorf("got %[1]q (%[1]s); want %[2]q (%[2]s)", got, tc.want)
diff --git a/internal/number/pattern.go b/internal/number/pattern.go index 881308e..89c2a1c 100644 --- a/internal/number/pattern.go +++ b/internal/number/pattern.go
@@ -39,19 +39,14 @@ // // This type is only intended for internal use. type Pattern struct { - // TODO: this struct can be packed a lot better than it is now. Should be - // possible to make it 32 bytes. - - Affix string // includes prefix and suffix. First byte is prefix length. - Offset uint16 // Offset into Affix for prefix and suffix - NegOffset uint16 // Offset into Affix for negative prefix and suffix or 0. - - FormatWidth uint16 - - PadRune rune - RoundingContext + Affix string // includes prefix and suffix. First byte is prefix length. + Offset uint16 // Offset into Affix for prefix and suffix + NegOffset uint16 // Offset into Affix for negative prefix and suffix or 0. + PadRune rune + FormatWidth uint16 + GroupingSize [2]uint8 Flags PatternFlag } @@ -60,45 +55,44 @@ // It contains all information needed to determine the "visible digits" as // required by the pluralization rules. type RoundingContext struct { - Precision int32 // maximum number of significant digits. - Scale int32 // maximum number of decimals after the dot. - - // if > 0, round to Increment * 10^-Scale - Increment uint32 // Use Min*Digits to determine scale + Increment uint32 // if > 0, round to Increment * 10^-scale() + // TODO: unify these two fields so that there is a more unambiguous meaning + // of how precision is handled. + MaxSignificantDigits int16 // -1 is infinite precision + MaxFractionDigits uint16 Mode RoundingMode DigitShift uint8 // Number of decimals to shift. Used for % and ‰. // Number of digits. - // TODO: consider using uint32 - MinIntegerDigits uint8 + MinIntegerDigits uint8 + MaxIntegerDigits uint8 MinFractionDigits uint8 - MaxFractionDigits uint8 MinSignificantDigits uint8 - MaxSignificantDigits uint8 MinExponentDigits uint8 } -func (r *RoundingContext) update() { - if r.Scale > 0 { - r.SetScale(int(r.Scale)) +func (r *RoundingContext) scale() int { + // scale is 0 when precision is set. + if r.MaxSignificantDigits != 0 { + return 0 } - if r.Precision > 0 { - r.SetPrecision(int(r.Precision)) - } + return int(r.MaxFractionDigits) } +func (r *RoundingContext) precision() int { return int(r.MaxSignificantDigits) } + // SetScale fixes the RoundingContext to a fixed number of fraction digits. func (r *RoundingContext) SetScale(scale int) { r.MinFractionDigits = uint8(scale) - r.MaxFractionDigits = uint8(scale) + r.MaxFractionDigits = uint16(scale) } func (r *RoundingContext) SetPrecision(prec int) { - r.MaxSignificantDigits = uint8(prec) + r.MaxSignificantDigits = int16(prec) } func (r *RoundingContext) isScientific() bool { @@ -420,7 +414,7 @@ func (p *parser) normalizeSigDigitsWithExponent() state { p.MinIntegerDigits, p.MaxIntegerDigits = 1, 1 p.MinFractionDigits = p.MinSignificantDigits - 1 - p.MaxFractionDigits = p.MaxSignificantDigits - 1 + p.MaxFractionDigits = uint16(p.MaxSignificantDigits) - 1 p.MinSignificantDigits, p.MaxSignificantDigits = 0, 0 return p.exponent }
diff --git a/internal/number/tables.go b/internal/number/tables.go index b140234..2cf16f5 100644 --- a/internal/number/tables.go +++ b/internal/number/tables.go
@@ -846,323 +846,291 @@ 0x04, 0x04, } // Size: 778 bytes -var formats = []Pattern{Pattern{Affix: "", +var formats = []Pattern{Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x0, + MinIntegerDigits: 0x0, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "", Offset: 0x0, NegOffset: 0x0, - FormatWidth: 0x0, PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, + FormatWidth: 0x0, + GroupingSize: [2]uint8{0x0, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x3, + Mode: 0x0, + DigitShift: 0x0, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x9, + GroupingSize: [2]uint8{0x3, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x0, + MinIntegerDigits: 0x0, + MaxIntegerDigits: 0x1, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x1}, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x3, + GroupingSize: [2]uint8{0x0, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x2, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "\x00\x03\u00a0%", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x7, + GroupingSize: [2]uint8{0x3, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x2, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "\x00\x01%", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x6, + GroupingSize: [2]uint8{0x3, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x3, + Mode: 0x0, + DigitShift: 0x0, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0xc, + GroupingSize: [2]uint8{0x3, + 0x2}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x2, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "\x00\x01%", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x9, + GroupingSize: [2]uint8{0x3, + 0x2}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x2, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "\x00\x03\u00a0%", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0xa, + GroupingSize: [2]uint8{0x3, + 0x2}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x6, + Mode: 0x0, + DigitShift: 0x0, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x9, + GroupingSize: [2]uint8{0x0, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x6, + Mode: 0x0, + DigitShift: 0x0, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x6, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x3}, + Affix: "", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0xd, + GroupingSize: [2]uint8{0x0, + 0x0}, + Flags: 0x4}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x2, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "\x00\x01%", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x3, + GroupingSize: [2]uint8{0x0, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x2, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "\x03%\u00a0\x00", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x7, + GroupingSize: [2]uint8{0x3, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x2, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "\x03%\u00a0\x00\x04%\u00a0-\x00", + Offset: 0x0, + NegOffset: 0x5, + PadRune: 0, + FormatWidth: 0x7, + GroupingSize: [2]uint8{0x3, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x0, + MinIntegerDigits: 0x0, + MaxIntegerDigits: 0x1, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x1}, + Affix: "\x01[\x01]", + Offset: 0x0, + NegOffset: 0x0, + PadRune: 0, + FormatWidth: 0x5, + GroupingSize: [2]uint8{0x0, + 0x0}, + Flags: 0x0}, + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, DigitShift: 0x0, MinIntegerDigits: 0x0, MaxIntegerDigits: 0x0, MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x0, - 0x0}, - Flags: 0x0}, - Pattern{Affix: "", + Affix: "", Offset: 0x0, NegOffset: 0x0, - FormatWidth: 0x9, PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x0, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x3, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x3, - 0x0}, - Flags: 0x0}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x3, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x0, - MinIntegerDigits: 0x0, - MaxIntegerDigits: 0x1, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x1}, - GroupingSize: [2]uint8{0x0, - 0x0}, - Flags: 0x0}, - Pattern{Affix: "\x00\x03\u00a0%", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x7, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x2, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x3, - 0x0}, - Flags: 0x0}, - Pattern{Affix: "\x00\x01%", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x6, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x2, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x3, - 0x0}, - Flags: 0x0}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0xc, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x0, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x3, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x3, - 0x2}, - Flags: 0x0}, - Pattern{Affix: "\x00\x01%", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x9, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x2, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x3, - 0x2}, - Flags: 0x0}, - Pattern{Affix: "\x00\x03\u00a0%", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0xa, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x2, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x3, - 0x2}, - Flags: 0x0}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x9, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x0, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x6, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x0, - 0x0}, - Flags: 0x0}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0xd, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x0, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x6, - MaxFractionDigits: 0x6, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x3}, - GroupingSize: [2]uint8{0x0, - 0x0}, - Flags: 0x4}, - Pattern{Affix: "\x00\x01%", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x3, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x2, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x0, - 0x0}, - Flags: 0x0}, - Pattern{Affix: "\x03%\u00a0\x00", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x7, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x2, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x3, - 0x0}, - Flags: 0x0}, - Pattern{Affix: "\x03%\u00a0\x00\x04%\u00a0-\x00", - Offset: 0x0, - NegOffset: 0x5, - FormatWidth: 0x7, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x2, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, - GroupingSize: [2]uint8{0x3, - 0x0}, - Flags: 0x0}, - Pattern{Affix: "\x01[\x01]", - Offset: 0x0, - NegOffset: 0x0, - FormatWidth: 0x5, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x0, - MinIntegerDigits: 0x0, - MaxIntegerDigits: 0x1, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x1}, - GroupingSize: [2]uint8{0x0, - 0x0}, - Flags: 0x0}, - Pattern{Affix: "", - Offset: 0x0, - NegOffset: 0x0, FormatWidth: 0x1, - PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x0, - MinIntegerDigits: 0x0, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, GroupingSize: [2]uint8{0x0, 0x0}, Flags: 0x0}, - Pattern{Affix: "\x01%\x00", + Pattern{RoundingContext: RoundingContext{Increment: 0x0, + MaxSignificantDigits: 0, + MaxFractionDigits: 0x0, + Mode: 0x0, + DigitShift: 0x2, + MinIntegerDigits: 0x1, + MaxIntegerDigits: 0x0, + MinFractionDigits: 0x0, + MinSignificantDigits: 0x0, + MinExponentDigits: 0x0}, + Affix: "\x01%\x00", Offset: 0x0, NegOffset: 0x0, - FormatWidth: 0x6, PadRune: 0, - RoundingContext: RoundingContext{Mode: 0x0, - Precision: 0, - Scale: 0, - Increment: 0x0, - DigitShift: 0x2, - MinIntegerDigits: 0x1, - MaxIntegerDigits: 0x0, - MinFractionDigits: 0x0, - MaxFractionDigits: 0x0, - MinSignificantDigits: 0x0, - MaxSignificantDigits: 0x0, - MinExponentDigits: 0x0}, + FormatWidth: 0x6, GroupingSize: [2]uint8{0x3, 0x0}, Flags: 0x0}}
diff --git a/message/fmt_test.go b/message/fmt_test.go index 0dbedcb..b22420d 100755 --- a/message/fmt_test.go +++ b/message/fmt_test.go
@@ -565,8 +565,8 @@ // old test/fmt_test.go {"%e", 1.0, "1.000000\u202f×\u202f10⁰⁰"}, - {"%e", 1234.5678e3, "1.234570\u202f×\u202f10⁰⁶"}, - {"%e", 1234.5678e-8, "1.234570\u202f×\u202f10⁻⁰⁵"}, + {"%e", 1234.5678e3, "1.234568\u202f×\u202f10⁰⁶"}, + {"%e", 1234.5678e-8, "1.234568\u202f×\u202f10⁻⁰⁵"}, {"%e", -7.0, "-7.000000\u202f×\u202f10⁰⁰"}, {"%e", -1e-9, "-1.000000\u202f×\u202f10⁻⁰⁹"}, {"%f", 1234.5678e3, "1,234,567.800000"}, @@ -580,8 +580,8 @@ {"%g", -1e-9, "-1\u202f×\u202f10⁻⁰⁹"}, {"%g", float32(-1e-9), "-1\u202f×\u202f10⁻⁰⁹"}, {"%E", 1.0, "1.000000\u202f×\u202f10⁰⁰"}, - {"%E", 1234.5678e3, "1.234570\u202f×\u202f10⁰⁶"}, - {"%E", 1234.5678e-8, "1.234570\u202f×\u202f10⁻⁰⁵"}, + {"%E", 1234.5678e3, "1.234568\u202f×\u202f10⁰⁶"}, + {"%E", 1234.5678e-8, "1.234568\u202f×\u202f10⁻⁰⁵"}, {"%E", -7.0, "-7.000000\u202f×\u202f10⁰⁰"}, {"%E", -1e-9, "-1.000000\u202f×\u202f10⁻⁰⁹"}, {"%G", 1234.5678e3, "1.2345678\u202f×\u202f10⁰⁶"},
diff --git a/message/print.go b/message/print.go index 8c8a23f..c0bef3f 100644 --- a/message/print.go +++ b/message/print.go
@@ -237,7 +237,7 @@ if p.fmt.sharp || p.fmt.sharpV { p.fmt.fmt_float(v, size, verb, -1) } else { - p.fmtVariableFloat(v, size, -1) + p.fmtVariableFloat(v, size) } case 'e', 'E': if p.fmt.sharp || p.fmt.sharpV { @@ -284,7 +284,7 @@ f.MinIntegerDigits = 1 f.MaxIntegerDigits = 0 f.MinFractionDigits = uint8(minFrac) - f.MaxFractionDigits = uint8(maxFrac) + f.MaxFractionDigits = uint16(maxFrac) p.setFlags(f) f.PadRune = 0 if p.fmt.widPresent { @@ -308,8 +308,13 @@ func (p *printer) initScientific(minFrac, maxFrac int) { f := &p.toScientific - f.MinFractionDigits = uint8(minFrac) - f.MaxFractionDigits = uint8(maxFrac) + if maxFrac < 0 { + f.SetPrecision(maxFrac) + } else { + f.SetPrecision(maxFrac + 1) + f.MinFractionDigits = uint8(minFrac) + f.MaxFractionDigits = uint16(maxFrac) + } f.MinExponentDigits = 2 p.setFlags(f) f.PadRune = 0 @@ -328,8 +333,6 @@ func (p *printer) fmtDecimalInt(v uint64, isSigned bool) { var d number.Decimal - p.toDecimal.RoundingContext.Scale = 0 - d.ConvertInt(&p.toDecimal.RoundingContext, isSigned, v) f := &p.toDecimal if p.fmt.precPresent { @@ -344,6 +347,7 @@ } else { p.initDecimal(0, 0) } + d.ConvertInt(p.toDecimal.RoundingContext, isSigned, v) out := p.toDecimal.Format([]byte(nil), &d) p.Buffer.Write(out) @@ -354,22 +358,21 @@ if p.fmt.precPresent { prec = p.fmt.prec } - p.toDecimal.RoundingContext.Scale = int32(prec) - d.ConvertFloat(&p.toDecimal.RoundingContext, v, size) - p.initDecimal(prec, prec) + d.ConvertFloat(p.toDecimal.RoundingContext, v, size) out := p.toDecimal.Format([]byte(nil), &d) p.Buffer.Write(out) } -func (p *printer) fmtVariableFloat(v float64, size, prec int) { +func (p *printer) fmtVariableFloat(v float64, size int) { + prec := -1 if p.fmt.precPresent { prec = p.fmt.prec } var d number.Decimal - p.toScientific.RoundingContext.Precision = int32(prec) - d.ConvertFloat(&p.toScientific.RoundingContext, v, size) + p.initScientific(0, prec) + d.ConvertFloat(p.toScientific.RoundingContext, v, size) // Copy logic of 'g' formatting from strconv. It is simplified a bit as // we don't have to mind having prec > len(d.Digits). @@ -407,10 +410,9 @@ if p.fmt.precPresent { prec = p.fmt.prec } - p.toScientific.RoundingContext.Precision = int32(prec) - d.ConvertFloat(&p.toScientific.RoundingContext, v, size) - p.initScientific(prec, prec) + rc := p.toScientific.RoundingContext + d.ConvertFloat(rc, v, size) out := p.toScientific.Format([]byte(nil), &d) p.Buffer.Write(out)