{32, 'g', -1, "32"},
{32, 'g', 0, "3e+01"},
- {100, 'x', -1, "%x"},
+ // {100, 'x', -1, "%x"},
// {math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
// {-math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
{"-1024.0", 64, 'p', 0, "-0x.8p+11"},
// unsupported format
- {"3.14", 64, 'x', 0, "%x"},
- {"-3.14", 64, 'x', 0, "%x"},
+ //{"3.14", 64, 'x', 0, "%x"},
+ //{"-3.14", 64, 'x', 0, "%x"},
} {
f, _, err := ParseFloat(test.x, 0, test.prec, ToNearestEven)
if err != nil {
// 'e' (-d.dddde±dd, a decimal exponent),
// 'E' (-d.ddddE±dd, a decimal exponent),
// 'f' (-ddd.dddd, no exponent),
-// 'g' ('e' for large exponents, 'f' otherwise), or
-// 'G' ('E' for large exponents, 'f' otherwise).
+// 'g' ('e' for large exponents, 'f' otherwise),
+// 'G' ('E' for large exponents, 'f' otherwise),
+// 'x' (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or
+// 'X' (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent).
//
// The precision prec controls the number of digits (excluding the exponent)
-// printed by the 'e', 'E', 'f', 'g', and 'G' formats.
-// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
+// printed by the 'e', 'E', 'f', 'g', 'G', 'x', and 'X' formats.
+// For 'e', 'E', 'f', 'x', and 'X', it is the number of digits after the decimal point.
// For 'g' and 'G' it is the maximum number of significant digits (trailing
// zeros are removed).
// The special precision -1 uses the smallest number of digits
}
exp += flt.bias
- // Pick off easy binary format.
+ // Pick off easy binary, hex formats.
if fmt == 'b' {
return fmtB(dst, neg, mant, exp, flt)
}
+ if fmt == 'x' || fmt == 'X' {
+ return fmtX(dst, prec, fmt, neg, mant, exp, flt)
+ }
if !optimize {
return bigFtoa(dst, prec, fmt, neg, mant, exp, flt)
return dst
}
+// %x: -0x1.yyyyyyyyp±ddd or -0x0p+0. (y is hex digit, d is decimal digit)
+func fmtX(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
+ if mant == 0 {
+ exp = 0
+ }
+
+ // Shift digits so leading 1 (if any) is at bit 1<<60.
+ mant <<= 60 - flt.mantbits
+ for mant != 0 && mant&(1<<60) == 0 {
+ mant <<= 1
+ exp--
+ }
+
+ // Round if requested.
+ if prec >= 0 && prec < 15 {
+ shift := uint(prec * 4)
+ extra := (mant << shift) & (1<<60 - 1)
+ mant >>= 60 - shift
+ if extra|(mant&1) > 1<<59 {
+ mant++
+ }
+ mant <<= 60 - shift
+ if mant&(1<<61) != 0 {
+ // Wrapped around.
+ mant >>= 1
+ exp++
+ }
+ }
+
+ hex := lowerhex
+ if fmt == 'X' {
+ hex = upperhex
+ }
+
+ // sign, 0x, leading digit
+ if neg {
+ dst = append(dst, '-')
+ }
+ dst = append(dst, '0', fmt, '0'+byte((mant>>60)&1))
+
+ // .fraction
+ mant <<= 4 // remove leading 0 or 1
+ if prec < 0 && mant != 0 {
+ dst = append(dst, '.')
+ for mant != 0 {
+ dst = append(dst, hex[(mant>>60)&15])
+ mant <<= 4
+ }
+ } else if prec > 0 {
+ dst = append(dst, '.')
+ for i := 0; i < prec; i++ {
+ dst = append(dst, hex[(mant>>60)&15])
+ mant <<= 4
+ }
+ }
+
+ // p±
+ ch := byte('P')
+ if fmt == lower(fmt) {
+ ch = 'p'
+ }
+ dst = append(dst, ch)
+ if exp < 0 {
+ ch = '-'
+ exp = -exp
+ } else {
+ ch = '+'
+ }
+ dst = append(dst, ch)
+
+ // dd or ddd or dddd
+ switch {
+ case exp < 100:
+ dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
+ case exp < 1000:
+ dst = append(dst, byte(exp/100)+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
+ default:
+ dst = append(dst, byte(exp/1000)+'0', byte(exp/100)%10+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0')
+ }
+
+ return dst
+}
+
func min(a, b int) int {
if a < b {
return a
{1, 'f', 5, "1.00000"},
{1, 'g', 5, "1"},
{1, 'g', -1, "1"},
+ {1, 'x', -1, "0x1p+00"},
+ {1, 'x', 5, "0x1.00000p+00"},
{20, 'g', -1, "20"},
+ {20, 'x', -1, "0x1.4p+04"},
{1234567.8, 'g', -1, "1.2345678e+06"},
+ {1234567.8, 'x', -1, "0x1.2d687cccccccdp+20"},
{200000, 'g', -1, "200000"},
+ {200000, 'x', -1, "0x1.86ap+17"},
+ {200000, 'X', -1, "0X1.86AP+17"},
{2000000, 'g', -1, "2e+06"},
// g conversion and zero suppression
{0, 'f', 5, "0.00000"},
{0, 'g', 5, "0"},
{0, 'g', -1, "0"},
+ {0, 'x', 5, "0x0.00000p+00"},
{-1, 'e', 5, "-1.00000e+00"},
{-1, 'f', 5, "-1.00000"},
{32, 'g', -1, "32"},
{32, 'g', 0, "3e+01"},
- {100, 'x', -1, "%x"},
+ {100, 'x', -1, "0x1.9p+06"},
+ {100, 'y', -1, "%y"},
{math.NaN(), 'g', -1, "NaN"},
{-math.NaN(), 'g', -1, "NaN"},
// Issue 2625.
{383260575764816448, 'f', 0, "383260575764816448"},
{383260575764816448, 'g', -1, "3.8326057576481645e+17"},
+
+ // rounding
+ {2.275555555555555, 'x', -1, "0x1.23456789abcdep+01"},
+ {2.275555555555555, 'x', 0, "0x1p+01"},
+ {2.275555555555555, 'x', 2, "0x1.23p+01"},
+ {2.275555555555555, 'x', 16, "0x1.23456789abcde000p+01"},
+ {2.275555555555555, 'x', 21, "0x1.23456789abcde00000000p+01"},
+ {2.2755555510520935, 'x', -1, "0x1.2345678p+01"},
+ {2.2755555510520935, 'x', 6, "0x1.234568p+01"},
+ {2.275555431842804, 'x', -1, "0x1.2345668p+01"},
+ {2.275555431842804, 'x', 6, "0x1.234566p+01"},
+ {3.999969482421875, 'x', -1, "0x1.ffffp+01"},
+ {3.999969482421875, 'x', 4, "0x1.ffffp+01"},
+ {3.999969482421875, 'x', 3, "0x1.000p+02"},
+ {3.999969482421875, 'x', 2, "0x1.00p+02"},
+ {3.999969482421875, 'x', 1, "0x1.0p+02"},
+ {3.999969482421875, 'x', 0, "0x1p+02"},
}
func TestFtoa(t *testing.T) {
"unicode/utf8"
)
-const lowerhex = "0123456789abcdef"
+const (
+ lowerhex = "0123456789abcdef"
+ upperhex = "0123456789ABCDEF"
+)
func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly))