Commit f36e1ada authored by Emmanuel Odeke's avatar Emmanuel Odeke Committed by Robert Griesemer

math/big: implement Float.Scan, type assert fmt interfaces to enforce docs

Implements Float.Scan which satisfies fmt.Scanner interface.
Also enforces docs' interface implementation claims with compile time
type assertions, that is:
+ Float always implements fmt.Formatter and fmt.Scanner
+ Int always implements fmt.Formatter and fmt.Scanner
+ Rat always implements fmt.Formatter
which will ensure that the API claims are strictly matched.

Also note that Float.Scan doesn't handle ±Inf.

Fixes #17391

Change-Id: I3d3dfbe7f602066975c7a7794fe25b4c645440ce
Reviewed-on: https://go-review.googlesource.com/30723Reviewed-by: 's avatarRobert Griesemer <gri@golang.org>
parent ead08e91
......@@ -51,6 +51,19 @@ func ExampleInt_Scan() {
// Output: 18446744073709551617
}
func ExampleFloat_Scan() {
// The Scan function is rarely used directly;
// the fmt package recognizes it as an implementation of fmt.Scanner.
f := new(big.Float)
_, err := fmt.Sscan("1.19282e99", f)
if err != nil {
log.Println("error scanning value:", err)
} else {
fmt.Println(f)
}
// Output: 1.19282e+99
}
// This example demonstrates how to use big.Int to compute the smallest
// Fibonacci number with 100 decimal digits and to test whether it is prime.
func Example_fibonacci() {
......
......@@ -12,6 +12,8 @@ import (
"strings"
)
var floatZero Float
// SetString sets z to the value of s and returns z and a boolean indicating
// success. s must be a floating-point number of the same format as accepted
// by Parse, with base argument 0. The entire string (not just a prefix) must
......@@ -276,3 +278,16 @@ func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
}
var _ fmt.Scanner = &floatZero // *Float must implement fmt.Scanner
// Scan is a support routine for fmt.Scanner; it sets z to the value of
// the scanned number. It accepts formats whose verbs are supported by
// fmt.Scan for floating point values, which are:
// 'b' (binary), 'e', 'E', 'f', 'F', 'g' and 'G'.
// Scan doesn't handle ±Inf.
func (z *Float) Scan(s fmt.ScanState, ch rune) error {
s.SkipSpace()
_, _, err := z.scan(byteReader{s}, 0)
return err
}
......@@ -5,6 +5,7 @@
package big
import (
"bytes"
"fmt"
"math"
"strconv"
......@@ -665,3 +666,54 @@ func BenchmarkParseFloatLargeExp(b *testing.B) {
}
}
}
func TestFloatScan(t *testing.T) {
var floatScanTests = []struct {
input string
format string
output string
remaining int
wantErr bool
}{
0: {"10.0", "%f", "10", 0, false},
1: {"23.98+2.0", "%v", "23.98", 4, false},
2: {"-1+1", "%v", "-1", 2, false},
3: {" 00000", "%v", "0", 0, false},
4: {"-123456p-78", "%b", "-4.084816388e-19", 0, false},
5: {"+123", "%b", "123", 0, false},
6: {"-1.234e+56", "%e", "-1.234e+56", 0, false},
7: {"-1.234E-56", "%E", "-1.234e-56", 0, false},
8: {"-1.234e+567", "%g", "-1.234e+567", 0, false},
9: {"+1234567891011.234", "%G", "1.234567891e+12", 0, false},
// Scan doesn't handle ±Inf.
10: {"Inf", "%v", "", 3, true},
11: {"-Inf", "%v", "", 3, true},
12: {"-Inf", "%v", "", 3, true},
}
var buf bytes.Buffer
for i, test := range floatScanTests {
x := new(Float)
buf.Reset()
buf.WriteString(test.input)
_, err := fmt.Fscanf(&buf, test.format, x)
if test.wantErr {
if err == nil {
t.Errorf("#%d want non-nil err", i)
}
continue
}
if err != nil {
t.Errorf("#%d error: %s", i, err)
}
if x.String() != test.output {
t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
}
if buf.Len() != test.remaining {
t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
}
}
}
......@@ -376,6 +376,8 @@ func min(x, y int) int {
return y
}
var _ fmt.Formatter = &floatZero // *Float must implement fmt.Formatter
// Format implements fmt.Formatter. It accepts all the regular
// formats for floating-point numbers ('b', 'e', 'E', 'f', 'F',
// 'g', 'G') as well as 'p' and 'v'. See (*Float).Text for the
......
......@@ -52,6 +52,8 @@ func writeMultiple(s fmt.State, text string, count int) {
}
}
var _ fmt.Formatter = intOne // *Int must implement fmt.Formatter
// Format implements fmt.Formatter. It accepts the formats
// 'b' (binary), 'o' (octal), 'd' (decimal), 'x' (lowercase
// hexadecimal), and 'X' (uppercase hexadecimal).
......@@ -223,6 +225,8 @@ func (r byteReader) UnreadByte() error {
return r.UnreadRune()
}
var _ fmt.Scanner = intOne // *Int must implement fmt.Scanner
// Scan is a support routine for fmt.Scanner; it sets z to the value of
// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
......
......@@ -18,6 +18,9 @@ func ratTok(ch rune) bool {
return strings.ContainsRune("+-/0123456789.eE", ch)
}
var ratZero Rat
var _ fmt.Scanner = &ratZero // *Rat must implement fmt.Scanner
// Scan is a support routine for fmt.Scanner. It accepts the formats
// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment