aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2010-11-30 12:53:42 -0800
committerRob Pike <r@golang.org>2010-11-30 12:53:42 -0800
commit448c05d7c8f559e3d8ea0b75b57bff5178e38704 (patch)
tree2738f84ac584a75d29d7215ed98ed406200ae072
parentb3896462435fde33f20b36131e4a94f61a9fe803 (diff)
downloadgo-448c05d7c8f559e3d8ea0b75b57bff5178e38704.tar.gz
go-448c05d7c8f559e3d8ea0b75b57bff5178e38704.zip
strconv: Atof on Infs and NaNs
R=rsc CC=golang-dev https://golang.org/cl/3359041
-rw-r--r--src/pkg/strconv/atof.go42
-rw-r--r--src/pkg/strconv/atof_test.go10
2 files changed, 52 insertions, 0 deletions
diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go
index 262a8b53c7..90ca7c4f9c 100644
--- a/src/pkg/strconv/atof.go
+++ b/src/pkg/strconv/atof.go
@@ -19,6 +19,40 @@ import (
var optimize = true // can change for testing
+func equalIgnoreCase(s1, s2 string) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i := 0; i < len(s1); i++ {
+ c1 := s1[i]
+ if 'A' <= c1 && c1 <= 'Z' {
+ c1 += 'a' - 'A'
+ }
+ c2 := s2[i]
+ if 'A' <= c2 && c2 <= 'Z' {
+ c2 += 'a' - 'A'
+ }
+ if c1 != c2 {
+ return false
+ }
+ }
+ return true
+}
+
+func special(s string) (f float64, ok bool) {
+ switch {
+ case equalIgnoreCase(s, "nan"):
+ return math.NaN(), true
+ case equalIgnoreCase(s, "-inf"):
+ return math.Inf(-1), true
+ case equalIgnoreCase(s, "+inf"):
+ return math.Inf(1), true
+ case equalIgnoreCase(s, "inf"):
+ return math.Inf(1), true
+ }
+ return
+}
+
// TODO(rsc): Better truncation handling.
func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
i := 0
@@ -320,6 +354,10 @@ func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) {
// away from the largest floating point number of the given size,
// Atof32 returns f = ±Inf, err.Error = os.ERANGE.
func Atof32(s string) (f float32, err os.Error) {
+ if val, ok := special(s); ok {
+ return float32(val), nil
+ }
+
neg, d, trunc, ok := stringToDecimal(s)
if !ok {
return 0, &NumError{s, os.EINVAL}
@@ -341,6 +379,10 @@ func Atof32(s string) (f float32, err os.Error) {
// Except for the type of its result, its definition is the same as that
// of Atof32.
func Atof64(s string) (f float64, err os.Error) {
+ if val, ok := special(s); ok {
+ return val, nil
+ }
+
neg, d, trunc, ok := stringToDecimal(s)
if !ok {
return 0, &NumError{s, os.EINVAL}
diff --git a/src/pkg/strconv/atof_test.go b/src/pkg/strconv/atof_test.go
index 1f7543891f..2277ff61a6 100644
--- a/src/pkg/strconv/atof_test.go
+++ b/src/pkg/strconv/atof_test.go
@@ -37,6 +37,16 @@ var atoftests = []atofTest{
{"1e-20", "1e-20", nil},
{"625e-3", "0.625", nil},
+ // NaNs
+ {"nan", "NaN", nil},
+ {"NaN", "NaN", nil},
+ {"NAN", "NaN", nil},
+
+ // Infs
+ {"inf", "+Inf", nil},
+ {"-Inf", "-Inf", nil},
+ {"+INF", "+Inf", nil},
+
// largest float64
{"1.7976931348623157e308", "1.7976931348623157e+308", nil},
{"-1.7976931348623157e308", "-1.7976931348623157e+308", nil},