@@ -18,3 +18,145 @@ macro_rules! assert_approx_eq {
18
18
"{} is not approximately equal to {}" , * a, * b) ;
19
19
} )
20
20
}
21
+
22
+ macro_rules! from_str_radix_float_impl {
23
+ ( $T: ty) => {
24
+ fn from_str_radix( src: & str , radix: u32 )
25
+ -> Result <$T, ParseFloatError > {
26
+ use num:: FloatErrorKind :: * ;
27
+ use num:: ParseFloatError as PFE ;
28
+
29
+ // Special values
30
+ match src {
31
+ "inf" => return Ok ( Float :: infinity( ) ) ,
32
+ "-inf" => return Ok ( Float :: neg_infinity( ) ) ,
33
+ "NaN" => return Ok ( Float :: nan( ) ) ,
34
+ _ => { } ,
35
+ }
36
+
37
+ let ( is_positive, src) = match src. slice_shift_char( ) {
38
+ None => return Err ( PFE { kind: Empty } ) ,
39
+ Some ( ( '-' , "" ) ) => return Err ( PFE { kind: Empty } ) ,
40
+ Some ( ( '-' , src) ) => ( false , src) ,
41
+ Some ( ( _, _) ) => ( true , src) ,
42
+ } ;
43
+
44
+ // The significand to accumulate
45
+ let mut sig = if is_positive { 0.0 } else { -0.0 } ;
46
+ // Necessary to detect overflow
47
+ let mut prev_sig = sig;
48
+ let mut cs = src. chars( ) . enumerate( ) ;
49
+ // Exponent prefix and exponent index offset
50
+ let mut exp_info = None :: <( char , usize ) >;
51
+
52
+ // Parse the integer part of the significand
53
+ for ( i, c) in cs. by_ref( ) {
54
+ match c. to_digit( radix) {
55
+ Some ( digit) => {
56
+ // shift significand one digit left
57
+ sig = sig * ( radix as $T) ;
58
+
59
+ // add/subtract current digit depending on sign
60
+ if is_positive {
61
+ sig = sig + ( ( digit as isize ) as $T) ;
62
+ } else {
63
+ sig = sig - ( ( digit as isize ) as $T) ;
64
+ }
65
+
66
+ // Detect overflow by comparing to last value, except
67
+ // if we've not seen any non-zero digits.
68
+ if prev_sig != 0.0 {
69
+ if is_positive && sig <= prev_sig
70
+ { return Ok ( Float :: infinity( ) ) ; }
71
+ if !is_positive && sig >= prev_sig
72
+ { return Ok ( Float :: neg_infinity( ) ) ; }
73
+
74
+ // Detect overflow by reversing the shift-and-add process
75
+ if is_positive && ( prev_sig != ( sig - digit as $T) / radix as $T)
76
+ { return Ok ( Float :: infinity( ) ) ; }
77
+ if !is_positive && ( prev_sig != ( sig + digit as $T) / radix as $T)
78
+ { return Ok ( Float :: neg_infinity( ) ) ; }
79
+ }
80
+ prev_sig = sig;
81
+ } ,
82
+ None => match c {
83
+ 'e' | 'E' | 'p' | 'P' => {
84
+ exp_info = Some ( ( c, i + 1 ) ) ;
85
+ break ; // start of exponent
86
+ } ,
87
+ '.' => {
88
+ break ; // start of fractional part
89
+ } ,
90
+ _ => {
91
+ return Err ( PFE { kind: Invalid } ) ;
92
+ } ,
93
+ } ,
94
+ }
95
+ }
96
+
97
+ // If we are not yet at the exponent parse the fractional
98
+ // part of the significand
99
+ if exp_info. is_none( ) {
100
+ let mut power = 1.0 ;
101
+ for ( i, c) in cs. by_ref( ) {
102
+ match c. to_digit( radix) {
103
+ Some ( digit) => {
104
+ // Decrease power one order of magnitude
105
+ power = power / ( radix as $T) ;
106
+ // add/subtract current digit depending on sign
107
+ sig = if is_positive {
108
+ sig + ( digit as $T) * power
109
+ } else {
110
+ sig - ( digit as $T) * power
111
+ } ;
112
+ // Detect overflow by comparing to last value
113
+ if is_positive && sig < prev_sig
114
+ { return Ok ( Float :: infinity( ) ) ; }
115
+ if !is_positive && sig > prev_sig
116
+ { return Ok ( Float :: neg_infinity( ) ) ; }
117
+ prev_sig = sig;
118
+ } ,
119
+ None => match c {
120
+ 'e' | 'E' | 'p' | 'P' => {
121
+ exp_info = Some ( ( c, i + 1 ) ) ;
122
+ break ; // start of exponent
123
+ } ,
124
+ _ => {
125
+ return Err ( PFE { kind: Invalid } ) ;
126
+ } ,
127
+ } ,
128
+ }
129
+ }
130
+ }
131
+
132
+ // Parse and calculate the exponent
133
+ let exp = match exp_info {
134
+ Some ( ( c, offset) ) => {
135
+ let base = match c {
136
+ 'E' | 'e' if radix == 10 => 10.0 ,
137
+ 'P' | 'p' if radix == 16 => 2.0 ,
138
+ _ => return Err ( PFE { kind: Invalid } ) ,
139
+ } ;
140
+
141
+ // Parse the exponent as decimal integer
142
+ let src = & src[ offset..] ;
143
+ let ( is_positive, exp) = match src. slice_shift_char( ) {
144
+ Some ( ( '-' , src) ) => ( false , src. parse:: <usize >( ) ) ,
145
+ Some ( ( '+' , src) ) => ( true , src. parse:: <usize >( ) ) ,
146
+ Some ( ( _, _) ) => ( true , src. parse:: <usize >( ) ) ,
147
+ None => return Err ( PFE { kind: Invalid } ) ,
148
+ } ;
149
+
150
+ match ( is_positive, exp) {
151
+ ( true , Ok ( exp) ) => base. powi( exp as i32 ) ,
152
+ ( false , Ok ( exp) ) => 1.0 / base. powi( exp as i32 ) ,
153
+ ( _, Err ( _) ) => return Err ( PFE { kind: Invalid } ) ,
154
+ }
155
+ } ,
156
+ None => 1.0 , // no exponent
157
+ } ;
158
+
159
+ Ok ( sig * exp)
160
+ }
161
+ }
162
+ }
0 commit comments