@@ -12,7 +12,7 @@ package strconv
12
12
13
13
import "math"
14
14
15
- var optimize = true // can change for testing
15
+ var optimize = true // set to false to force slow-path conversions for testing
16
16
17
17
func equalIgnoreCase (s1 , s2 string ) bool {
18
18
if len (s1 ) != len (s2 ) {
@@ -119,7 +119,7 @@ func (b *decimal) set(s string) (ok bool) {
119
119
// just be sure to move the decimal point by
120
120
// a lot (say, 100000). it doesn't matter if it's
121
121
// not the exact number.
122
- if i < len (s ) && (s [i ] == 'e' || s [ i ] == 'E' ) {
122
+ if i < len (s ) && lower (s [i ]) == 'e' {
123
123
i ++
124
124
if i >= len (s ) {
125
125
return
@@ -152,10 +152,9 @@ func (b *decimal) set(s string) (ok bool) {
152
152
}
153
153
154
154
// readFloat reads a decimal mantissa and exponent from a float
155
- // string representation. It sets ok to false if the number could
155
+ // string representation. It returns ok== false if the number could
156
156
// not fit return types or is invalid.
157
- func readFloat (s string ) (mantissa uint64 , exp int , neg , trunc , ok bool ) {
158
- const uint64digits = 19
157
+ func readFloat (s string ) (mantissa uint64 , exp int , neg , trunc , hex , ok bool ) {
159
158
i := 0
160
159
161
160
// optional sign
@@ -171,6 +170,16 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
171
170
}
172
171
173
172
// digits
173
+ base := uint64 (10 )
174
+ maxMantDigits := 19 // 10^19 fits in uint64
175
+ expChar := byte ('e' )
176
+ if i + 2 < len (s ) && s [i ] == '0' && lower (s [i + 1 ]) == 'x' {
177
+ base = 16
178
+ maxMantDigits = 16 // 16^16 fits in uint64
179
+ i += 2
180
+ expChar = 'p'
181
+ hex = true
182
+ }
174
183
sawdot := false
175
184
sawdigits := false
176
185
nd := 0
@@ -193,11 +202,23 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
193
202
continue
194
203
}
195
204
nd ++
196
- if ndMant < uint64digits {
197
- mantissa *= 10
205
+ if ndMant < maxMantDigits {
206
+ mantissa *= base
198
207
mantissa += uint64 (c - '0' )
199
208
ndMant ++
200
- } else if s [i ] != '0' {
209
+ } else if c != '0' {
210
+ trunc = true
211
+ }
212
+ continue
213
+
214
+ case base == 16 && 'a' <= lower (c ) && lower (c ) <= 'f' :
215
+ sawdigits = true
216
+ nd ++
217
+ if ndMant < maxMantDigits {
218
+ mantissa *= 16
219
+ mantissa += uint64 (lower (c ) - 'a' + 10 )
220
+ ndMant ++
221
+ } else {
201
222
trunc = true
202
223
}
203
224
continue
@@ -211,12 +232,17 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
211
232
dp = nd
212
233
}
213
234
235
+ if base == 16 {
236
+ dp *= 4
237
+ ndMant *= 4
238
+ }
239
+
214
240
// optional exponent moves decimal point.
215
241
// if we read a very large, very long number,
216
242
// just be sure to move the decimal point by
217
243
// a lot (say, 100000). it doesn't matter if it's
218
244
// not the exact number.
219
- if i < len (s ) && (s [i ] == 'e' || s [ i ] == 'E' ) {
245
+ if i < len (s ) && lower (s [i ]) == expChar {
220
246
i ++
221
247
if i >= len (s ) {
222
248
return
@@ -238,6 +264,9 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
238
264
}
239
265
}
240
266
dp += e * esign
267
+ } else if base == 16 {
268
+ // Must have exponent.
269
+ return
241
270
}
242
271
243
272
if i != len (s ) {
@@ -249,7 +278,6 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
249
278
}
250
279
ok = true
251
280
return
252
-
253
281
}
254
282
255
283
// decimal power of ten to binary power of two.
@@ -433,35 +461,109 @@ func atof32exact(mantissa uint64, exp int, neg bool) (f float32, ok bool) {
433
461
return
434
462
}
435
463
464
+ // atofHex converts the hex floating-point string s
465
+ // to a rounded float32 or float64 value (depending on flt==&float32info or flt==&float64info)
466
+ // and returns it as a float64.
467
+ // The string s has already been parsed into a mantissa, exponent, and sign (neg==true for negative).
468
+ // If trunc is true, trailing non-zero bits have been omitted from the mantissa.
469
+ func atofHex (s string , flt * floatInfo , mantissa uint64 , exp int , neg , trunc bool ) (float64 , error ) {
470
+ maxExp := 1 << flt .expbits + flt .bias - 2
471
+ minExp := flt .bias + 1
472
+ exp += int (flt .mantbits ) // mantissa now implicitly divided by 2^mantbits.
473
+
474
+ // Shift mantissa and exponent to bring representation into float range.
475
+ // Eventually we want a mantissa with a leading 1-bit followed by mantbits other bits.
476
+ // For rounding, we need two more, where the bottom bit represents
477
+ // whether that bit or any later bit was non-zero.
478
+ // (If the mantissa has already lost non-zero bits, trunc is true,
479
+ // and we OR in a 1 below after shifting left appropriately.)
480
+ for mantissa != 0 && mantissa >> (flt .mantbits + 2 ) == 0 {
481
+ mantissa <<= 1
482
+ exp --
483
+ }
484
+ if trunc {
485
+ mantissa |= 1
486
+ }
487
+ for mantissa >> (1 + flt .mantbits + 2 ) != 0 {
488
+ mantissa = mantissa >> 1 | mantissa & 1
489
+ exp ++
490
+ }
491
+
492
+ // If exponent is too negative,
493
+ // denormalize in hopes of making it representable.
494
+ // (The -2 is for the rounding bits.)
495
+ for mantissa > 1 && exp < minExp - 2 {
496
+ mantissa = mantissa >> 1 | mantissa & 1
497
+ exp ++
498
+ }
499
+
500
+ // Round using two bottom bits.
501
+ round := mantissa & 3
502
+ mantissa >>= 2
503
+ round |= mantissa & 1 // round to even (round up if mantissa is odd)
504
+ exp += 2
505
+ if round == 3 {
506
+ mantissa ++
507
+ if mantissa == 1 << (1 + flt .mantbits ) {
508
+ mantissa >>= 1
509
+ exp ++
510
+ }
511
+ }
512
+
513
+ if mantissa >> flt .mantbits == 0 { // Denormal or zero.
514
+ exp = flt .bias
515
+ }
516
+ var err error
517
+ if exp > maxExp { // infinity and range error
518
+ mantissa = 1 << flt .mantbits
519
+ exp = maxExp + 1
520
+ err = rangeError (fnParseFloat , s )
521
+ }
522
+
523
+ bits := mantissa & (1 << flt .mantbits - 1 )
524
+ bits |= uint64 ((exp - flt .bias )& (1 << flt .expbits - 1 )) << flt .mantbits
525
+ if neg {
526
+ bits |= 1 << flt .mantbits << flt .expbits
527
+ }
528
+ if flt == & float32info {
529
+ return float64 (math .Float32frombits (uint32 (bits ))), err
530
+ }
531
+ return math .Float64frombits (bits ), err
532
+ }
533
+
436
534
const fnParseFloat = "ParseFloat"
437
535
438
536
func atof32 (s string ) (f float32 , err error ) {
439
537
if val , ok := special (s ); ok {
440
538
return float32 (val ), nil
441
539
}
442
540
443
- if optimize {
444
- // Parse mantissa and exponent.
445
- mantissa , exp , neg , trunc , ok := readFloat (s )
446
- if ok {
447
- // Try pure floating-point arithmetic conversion.
448
- if ! trunc {
449
- if f , ok := atof32exact (mantissa , exp , neg ); ok {
450
- return f , nil
451
- }
541
+ mantissa , exp , neg , trunc , hex , ok := readFloat (s )
542
+ if hex && ok {
543
+ f , err := atofHex (s , & float32info , mantissa , exp , neg , trunc )
544
+ return float32 (f ), err
545
+ }
546
+
547
+ if optimize && ok {
548
+ // Try pure floating-point arithmetic conversion.
549
+ if ! trunc {
550
+ if f , ok := atof32exact (mantissa , exp , neg ); ok {
551
+ return f , nil
452
552
}
453
- // Try another fast path.
454
- ext := new (extFloat )
455
- if ok := ext .AssignDecimal (mantissa , exp , neg , trunc , & float32info ); ok {
456
- b , ovf := ext .floatBits (& float32info )
457
- f = math .Float32frombits (uint32 (b ))
458
- if ovf {
459
- err = rangeError (fnParseFloat , s )
460
- }
461
- return f , err
553
+ }
554
+ // Try another fast path.
555
+ ext := new (extFloat )
556
+ if ok := ext .AssignDecimal (mantissa , exp , neg , trunc , & float32info ); ok {
557
+ b , ovf := ext .floatBits (& float32info )
558
+ f = math .Float32frombits (uint32 (b ))
559
+ if ovf {
560
+ err = rangeError (fnParseFloat , s )
462
561
}
562
+ return f , err
463
563
}
464
564
}
565
+
566
+ // Slow fallback.
465
567
var d decimal
466
568
if ! d .set (s ) {
467
569
return 0 , syntaxError (fnParseFloat , s )
@@ -479,28 +581,31 @@ func atof64(s string) (f float64, err error) {
479
581
return val , nil
480
582
}
481
583
482
- if optimize {
483
- // Parse mantissa and exponent.
484
- mantissa , exp , neg , trunc , ok := readFloat (s )
485
- if ok {
486
- // Try pure floating-point arithmetic conversion.
487
- if ! trunc {
488
- if f , ok := atof64exact (mantissa , exp , neg ); ok {
489
- return f , nil
490
- }
584
+ mantissa , exp , neg , trunc , hex , ok := readFloat (s )
585
+ if hex && ok {
586
+ return atofHex (s , & float64info , mantissa , exp , neg , trunc )
587
+ }
588
+
589
+ if optimize && ok {
590
+ // Try pure floating-point arithmetic conversion.
591
+ if ! trunc {
592
+ if f , ok := atof64exact (mantissa , exp , neg ); ok {
593
+ return f , nil
491
594
}
492
- // Try another fast path.
493
- ext := new (extFloat )
494
- if ok := ext .AssignDecimal (mantissa , exp , neg , trunc , & float64info ); ok {
495
- b , ovf := ext .floatBits (& float64info )
496
- f = math .Float64frombits (b )
497
- if ovf {
498
- err = rangeError (fnParseFloat , s )
499
- }
500
- return f , err
595
+ }
596
+ // Try another fast path.
597
+ ext := new (extFloat )
598
+ if ok := ext .AssignDecimal (mantissa , exp , neg , trunc , & float64info ); ok {
599
+ b , ovf := ext .floatBits (& float64info )
600
+ f = math .Float64frombits (b )
601
+ if ovf {
602
+ err = rangeError (fnParseFloat , s )
501
603
}
604
+ return f , err
502
605
}
503
606
}
607
+
608
+ // Slow fallback.
504
609
var d decimal
505
610
if ! d .set (s ) {
506
611
return 0 , syntaxError (fnParseFloat , s )
@@ -518,9 +623,13 @@ func atof64(s string) (f float64, err error) {
518
623
// When bitSize=32, the result still has type float64, but it will be
519
624
// convertible to float32 without changing its value.
520
625
//
521
- // If s is well-formed and near a valid floating point number,
522
- // ParseFloat returns the nearest floating point number rounded
626
+ // ParseFloat accepts decimal and hexadecimal floating-point number syntax.
627
+ // If s is well-formed and near a valid floating-point number,
628
+ // ParseFloat returns the nearest floating-point number rounded
523
629
// using IEEE754 unbiased rounding.
630
+ // (Parsing a hexadecimal floating-point value only rounds when
631
+ // there are more bits in the hexadecimal representatiton than
632
+ // will fit in the mantissa.)
524
633
//
525
634
// The errors that ParseFloat returns have concrete type *NumError
526
635
// and include err.Num = s.
0 commit comments