@@ -424,69 +424,18 @@ pub fn float_to_str_common<T: Float>(
424
424
// Some constants for from_str_bytes_common's input validation,
425
425
// they define minimum radix values for which the character is a valid digit.
426
426
static DIGIT_P_RADIX : uint = ( 'p' as uint ) - ( 'a' as uint ) + 11 u;
427
- static DIGIT_I_RADIX : uint = ( 'i' as uint ) - ( 'a' as uint ) + 11 u;
428
427
static DIGIT_E_RADIX : uint = ( 'e' as uint ) - ( 'a' as uint ) + 11 u;
429
428
430
- /**
431
- * Parses a string as a number. This is meant to
432
- * be a common base implementation for all numeric string conversion
433
- * functions like `from_str()` or `from_str_radix()`.
434
- *
435
- * # Arguments
436
- * - `src` - The string to parse.
437
- * - `radix` - Which base to parse the number as. Accepts 2-36.
438
- * - `special` - Whether to accept special values like `inf`
439
- * and `NaN`. Can conflict with `radix`, see Failure.
440
- * - `exponent` - Which exponent format to accept. Options are:
441
- * - `ExpNone`: No Exponent, accepts just plain numbers like `42` or
442
- * `-8.2`.
443
- * - `ExpDec`: Accepts numbers with a decimal exponent like `42e5` or
444
- * `8.2E-2`. The exponent string itself is always base 10.
445
- * Can conflict with `radix`, see Failure.
446
- * - `ExpBin`: Accepts numbers with a binary exponent like `42P-8` or
447
- * `FFp128`. The exponent string itself is always base 10.
448
- * Can conflict with `radix`, see Failure.
449
- *
450
- * # Return value
451
- * Returns `Some(n)` if `buf` parses to a number n without overflowing, and
452
- * `None` otherwise, depending on the constraints set by the remaining
453
- * arguments.
454
- *
455
- * # Failure
456
- * - Fails if `radix` < 2 or `radix` > 36.
457
- * - Fails if `radix` > 14 and `exponent` is `ExpDec` due to conflict
458
- * between digit and exponent sign `'e'`.
459
- * - Fails if `radix` > 25 and `exponent` is `ExpBin` due to conflict
460
- * between digit and exponent sign `'p'`.
461
- * - Fails if `radix` > 18 and `special == true` due to conflict
462
- * between digit and lowest first character in `inf` and `NaN`, the `'i'`.
463
- */
464
- pub fn from_str_float < T : Float > (
465
- src : & str , radix : uint , special : bool , exponent : ExponentFormat ,
466
- ) -> Option < T > {
467
- match exponent {
468
- ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e'
469
- => panic ! ( "from_str_bytes_common: radix {} incompatible with \
470
- use of 'e' as decimal exponent", radix) ,
471
- ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p'
472
- => panic ! ( "from_str_bytes_common: radix {} incompatible with \
473
- use of 'p' as binary exponent", radix) ,
474
- _ if special && radix >= DIGIT_I_RADIX // first digit of 'inf'
475
- => panic ! ( "from_str_bytes_common: radix {} incompatible with \
476
- special values 'inf' and 'NaN'", radix) ,
477
- _ if ( radix as int ) < 2
478
- => panic ! ( "from_str_bytes_common: radix {} to low, \
479
- must lie in the range [2, 36]", radix) ,
480
- _ if ( radix as int ) > 36
481
- => panic ! ( "from_str_bytes_common: radix {} to high, \
482
- must lie in the range [2, 36]", radix) ,
483
- _ => ( )
484
- }
429
+ pub fn from_str_radix_float < T : Float > ( src : & str , radix : uint ) -> Option < T > {
430
+ assert ! ( radix >= 2 && radix <= 36 ,
431
+ "from_str_radix_float: must lie in the range `[2, 36]` - found {}" ,
432
+ radix) ;
485
433
486
434
let _0: T = num:: zero ( ) ;
487
435
let _1: T = num:: one ( ) ;
488
- let radix_gen : T = num:: cast ( radix as int ) . unwrap ( ) ;
436
+ let radix_t : T = num:: cast ( radix as int ) . unwrap ( ) ;
489
437
438
+ // Special values
490
439
match src {
491
440
"inf" => return Some ( Float :: infinity ( ) ) ,
492
441
"-inf" => return Some ( Float :: neg_infinity ( ) ) ,
@@ -501,125 +450,131 @@ pub fn from_str_float<T: Float>(
501
450
( Some ( _) , _) => ( true , src) ,
502
451
} ;
503
452
504
- // Initialize accumulator with signed zero for floating point parsing to
505
- // work
506
- let mut accum = if is_positive { _0 } else { -_1 } ;
507
- let mut last_accum = accum; // Necessary to detect overflow
508
- let mut cs = src. chars ( ) . enumerate ( ) ;
509
- let mut exp = None :: < ( char , uint ) > ;
453
+ // The significand to accumulate
454
+ let mut sig = if is_positive { _0 } else { -_1 } ;
455
+ // Necessary to detect overflow
456
+ let mut prev_sig = sig;
457
+ let mut cs = src. chars ( ) . enumerate ( ) ;
458
+ // Exponent prefix and exponent index offset
459
+ let mut exp_info = None :: < ( char , uint ) > ;
510
460
511
- // Parse integer part of number
461
+ // Parse the integer part of the significand
512
462
for ( i, c) in cs {
513
- match c {
514
- 'e' | 'E' | 'p' | 'P' => {
515
- exp = Some ( ( c, i + 1 ) ) ;
516
- break ; // start of exponent
517
- } ,
518
- '.' => {
519
- break ; // start of fractional part
520
- } ,
521
- c => match c. to_digit ( radix) {
522
- Some ( digit) => {
523
- // shift accum one digit left
524
- accum = accum * radix_gen;
525
-
526
- // add/subtract current digit depending on sign
527
- if is_positive {
528
- accum = accum + num:: cast ( digit as int ) . unwrap ( ) ;
529
- } else {
530
- accum = accum - num:: cast ( digit as int ) . unwrap ( ) ;
531
- }
463
+ match c. to_digit ( radix) {
464
+ Some ( digit) => {
465
+ // shift significand one digit left
466
+ sig = sig * radix_t;
467
+
468
+ // add/subtract current digit depending on sign
469
+ if is_positive {
470
+ sig = sig + num:: cast ( digit as int ) . unwrap ( ) ;
471
+ } else {
472
+ sig = sig - num:: cast ( digit as int ) . unwrap ( ) ;
473
+ }
532
474
533
- // Detect overflow by comparing to last value, except
534
- // if we've not seen any non-zero digits.
535
- if last_accum != _0 {
536
- if is_positive && accum <= last_accum { return Some ( Float :: infinity ( ) ) ; }
537
- if !is_positive && accum >= last_accum { return Some ( Float :: neg_infinity ( ) ) ; }
538
-
539
- // Detect overflow by reversing the shift-and-add process
540
- if is_positive &&
541
- ( last_accum != ( ( accum - num:: cast ( digit as int ) . unwrap ( ) ) / radix_gen) ) {
542
- return Some ( Float :: infinity ( ) ) ;
543
- }
544
- if !is_positive &&
545
- ( last_accum != ( ( accum + num:: cast ( digit as int ) . unwrap ( ) ) / radix_gen) ) {
546
- return Some ( Float :: neg_infinity ( ) ) ;
547
- }
548
- }
549
- last_accum = accum;
475
+ // Detect overflow by comparing to last value, except
476
+ // if we've not seen any non-zero digits.
477
+ if prev_sig != _0 {
478
+ if is_positive && sig <= prev_sig
479
+ { return Some ( Float :: infinity ( ) ) ; }
480
+ if !is_positive && sig >= prev_sig
481
+ { return Some ( Float :: neg_infinity ( ) ) ; }
482
+
483
+ // Detect overflow by reversing the shift-and-add process
484
+ let digit: T = num:: cast ( digit as int ) . unwrap ( ) ;
485
+ if is_positive && ( prev_sig != ( ( sig - digit) / radix_t) )
486
+ { return Some ( Float :: infinity ( ) ) ; }
487
+ if !is_positive && ( prev_sig != ( ( sig + digit) / radix_t) )
488
+ { return Some ( Float :: neg_infinity ( ) ) ; }
489
+ }
490
+ prev_sig = sig;
491
+ } ,
492
+ None => match c {
493
+ 'e' | 'E' | 'p' | 'P' => {
494
+ exp_info = Some ( ( c, i + 1 ) ) ;
495
+ break ; // start of exponent
496
+ } ,
497
+ '.' => {
498
+ break ; // start of fractional part
550
499
} ,
551
- None => {
552
- return None ; // invalid number
500
+ _ => {
501
+ return None ;
553
502
} ,
554
503
} ,
555
504
}
556
505
}
557
506
558
- // Parse fractional part of number
559
- // Skip if already reached start of exponent
560
- if exp . is_none ( ) {
507
+ // If we are not yet at the exponent parse the fractional
508
+ // part of the significand
509
+ if exp_info . is_none ( ) {
561
510
let mut power = _1;
562
511
for ( i, c) in cs {
563
- match c {
564
- 'e' | 'E' | 'p' | 'P' => {
565
- exp = Some ( ( c, i + 1 ) ) ;
566
- break ; // start of exponent
512
+ match c. to_digit ( radix) {
513
+ Some ( digit) => {
514
+ let digit: T = num:: cast ( digit) . unwrap ( ) ;
515
+ // Decrease power one order of magnitude
516
+ power = power / radix_t;
517
+ // add/subtract current digit depending on sign
518
+ sig = if is_positive {
519
+ sig + digit * power
520
+ } else {
521
+ sig - digit * power
522
+ } ;
523
+ // Detect overflow by comparing to last value
524
+ if is_positive && sig < prev_sig
525
+ { return Some ( Float :: infinity ( ) ) ; }
526
+ if !is_positive && sig > prev_sig
527
+ { return Some ( Float :: neg_infinity ( ) ) ; }
528
+ prev_sig = sig;
567
529
} ,
568
- c => match c. to_digit ( radix) {
569
- Some ( digit) => {
570
- let digit: T = num:: cast ( digit) . unwrap ( ) ;
571
-
572
- // Decrease power one order of magnitude
573
- power = power / radix_gen;
574
- // add/subtract current digit depending on sign
575
- accum = if is_positive {
576
- accum + digit * power
577
- } else {
578
- accum - digit * power
579
- } ;
580
- // Detect overflow by comparing to last value
581
- if is_positive && accum < last_accum { return Some ( Float :: infinity ( ) ) ; }
582
- if !is_positive && accum > last_accum { return Some ( Float :: neg_infinity ( ) ) ; }
583
- last_accum = accum;
530
+ None => match c {
531
+ 'e' | 'E' | 'p' | 'P' => {
532
+ exp_info = Some ( ( c, i + 1 ) ) ;
533
+ break ; // start of exponent
584
534
} ,
585
- None => {
535
+ _ => {
586
536
return None ; // invalid number
587
537
} ,
588
538
} ,
589
539
}
590
540
}
591
541
}
592
542
593
- let multiplier = match exp {
594
- None => {
595
- _1 // no exponent
596
- } ,
543
+ // Parse and calculate the exponent
544
+ let exp = match exp_info {
597
545
Some ( ( c, offset) ) => {
598
- let base: T = match ( c, exponent) {
599
- // c is never _ so don't need to handle specially
600
- ( 'e' , ExpDec ) | ( 'E' , ExpDec ) => num:: cast ( 10 u) . unwrap ( ) ,
601
- ( 'p' , ExpBin ) | ( 'P' , ExpBin ) => num:: cast ( 2 u) . unwrap ( ) ,
602
- _ => return None , // char doesn't fit given exponent format
546
+ let base: T = match c {
547
+ 'E' | 'e' if radix == 10 => num:: cast ( 10 u) . unwrap ( ) ,
548
+ 'P' | 'p' if radix == 16 => num:: cast ( 2 u) . unwrap ( ) ,
549
+ _ => return None ,
603
550
} ;
604
- // parse remaining string as decimal integer
605
- let exp = from_str :: < int > ( src[ offset..] ) ;
606
- match exp {
607
- Some ( exp_pow) if exp_pow < 0 => {
608
- _1 / num:: pow ( base, ( -exp_pow. to_int ( ) . unwrap ( ) ) as uint )
609
- } ,
610
- Some ( exp_pow) => {
611
- num:: pow ( base, exp_pow. to_int ( ) . unwrap ( ) as uint )
612
- } ,
613
- None => {
614
- return None ; // invalid exponent
615
- } ,
551
+
552
+ // Parse the exponent as decimal integer
553
+ let src = src[ offset..] ;
554
+ let ( is_positive, exp) = match src. slice_shift_char ( ) {
555
+ ( Some ( '-' ) , src) => ( false , from_str :: < uint > ( src) ) ,
556
+ ( Some ( '+' ) , src) => ( true , from_str :: < uint > ( src) ) ,
557
+ ( Some ( _) , _) => ( true , from_str :: < uint > ( src) ) ,
558
+ ( None , _) => return None ,
559
+ } ;
560
+
561
+ match ( is_positive, exp) {
562
+ ( true , Some ( exp) ) => num:: pow ( base, exp) ,
563
+ ( false , Some ( exp) ) => _1 / num:: pow ( base, exp) ,
564
+ ( _, None ) => return None ,
616
565
}
617
566
} ,
567
+ None => _1, // no exponent
618
568
} ;
619
- Some ( accum * multiplier)
569
+
570
+ Some ( sig * exp)
620
571
}
621
572
622
573
pub fn from_str_radix_int < T : Int > ( src : & str , radix : uint ) -> Option < T > {
574
+ assert ! ( radix >= 2 && radix <= 36 ,
575
+ "from_str_radix_int: must lie in the range `[2, 36]` - found {}" ,
576
+ radix) ;
577
+
623
578
fn cast < T : Int > ( x : uint ) -> T {
624
579
num:: cast ( x) . unwrap ( )
625
580
}
@@ -687,10 +642,9 @@ mod test {
687
642
assert_eq ! ( u, None ) ;
688
643
let s : Option < i16 > = from_str_radix_int ( "80000" , 10 ) ;
689
644
assert_eq ! ( s, None ) ;
690
- let f : Option < f32 > = from_str_float (
691
- "10000000000000000000000000000000000000000" , 10 , false , ExpNone ) ;
645
+ let f : Option < f32 > = from_str_radix_float ( "10000000000000000000000000000000000000000" , 10 ) ;
692
646
assert_eq ! ( f, Some ( Float :: infinity( ) ) )
693
- let fe : Option < f32 > = from_str_float ( "1e40" , 10 , false , ExpDec ) ;
647
+ let fe : Option < f32 > = from_str_radix_float ( "1e40" , 10 ) ;
694
648
assert_eq ! ( fe, Some ( Float :: infinity( ) ) )
695
649
}
696
650
}
0 commit comments