1
+ /**
2
+ * String conversions
3
+ */
4
+
1
5
fn float_to_str ( num : float , digits : uint ) -> str {
2
6
let accum = if num < 0.0 { num = -num; "-" } else { "" } ;
3
7
let trunc = num as uint ;
@@ -15,21 +19,180 @@ fn float_to_str(num: float, digits: uint) -> str {
15
19
ret accum;
16
20
}
17
21
22
+ /**
23
+ * Convert a string to a float
24
+ *
25
+ * This function accepts strings such as
26
+ * * "3.14"
27
+ * * "+3.14", equivalent to "3.14"
28
+ * * "-3.14"
29
+ * * "2.5E10", or equivalently, "2.5e10"
30
+ * * "2.5E-10"
31
+ * * "", or, equivalently, "." (understood as 0)
32
+ * * "5."
33
+ * * ".5", or, equivalently, "0.5"
34
+ *
35
+ * @param num A string, possibly empty.
36
+ * @return [NaN] if the string did not represent a valid number.
37
+ * @return Otherwise, the floating-point number represented [num].
38
+ */
18
39
fn str_to_float ( num : str ) -> float {
19
- let digits = str:: split ( num, '.' as u8 ) ;
20
- let total = int:: from_str ( digits[ 0 ] ) as float ;
21
-
22
- fn dec_val ( c : char ) -> int { ret ( c as int ) - ( '0' as int ) ; }
23
-
24
- let right = digits[ 1 ] ;
25
- let len = str:: char_len ( digits[ 1 ] ) ;
26
- let i = 1 u;
27
- while ( i < len) {
28
- total += dec_val ( str:: pop_char ( right) ) as float /
29
- ( int:: pow ( 10 , i) as float ) ;
30
- i += 1 u;
31
- }
32
- ret total;
40
+ let pos = 0 u; //Current byte position in the string.
41
+ //Used to walk the string in O(n).
42
+ let len = str:: byte_len ( num) ; //Length of the string, in bytes.
43
+
44
+ if len == 0 u { ret 0. ; }
45
+ let total = 0 f; //Accumulated result
46
+ let c = 'z' ; //Latest char.
47
+
48
+ //Determine if first char is '-'/'+'. Set [pos] and [neg] accordingly.
49
+ let neg = false ; //Sign of the result
50
+ alt str:: char_at ( num, 0 u) {
51
+ '-' {
52
+ neg = true ;
53
+ pos = 1 u;
54
+ }
55
+ '+' {
56
+ pos = 1 u;
57
+ }
58
+ _ { }
59
+ }
60
+
61
+ //Examine the following chars until '.', 'e', 'E'
62
+ while ( pos < len) {
63
+ let char_range = str:: char_range_at ( num, pos) ;
64
+ c = char_range. ch ;
65
+ pos = char_range. next ;
66
+ alt c {
67
+ '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' {
68
+ total = total * 10 f;
69
+ total += ( ( c as int ) - ( '0' as int ) ) as float ;
70
+ }
71
+ _ {
72
+ break;
73
+ }
74
+ }
75
+ }
76
+
77
+ if c == '.' { //Examine decimal part
78
+ let decimal = 1 . f ;
79
+ while ( pos < len) {
80
+ let char_range = str:: char_range_at ( num, pos) ;
81
+ c = char_range. ch ;
82
+ pos = char_range. next ;
83
+ alt c {
84
+ '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' {
85
+ decimal /= 10 . f ;
86
+ total += ( ( ( c as int ) - ( '0' as int ) ) as float ) * decimal;
87
+ }
88
+ _ {
89
+ break;
90
+ }
91
+ }
92
+ }
93
+ }
94
+
95
+ if ( c == 'e' ) | ( c == 'E' ) { //Examine exponent
96
+ let exponent = 0 u;
97
+ let neg_exponent = false ;
98
+ if ( pos < len) {
99
+ let char_range = str:: char_range_at ( num, pos) ;
100
+ c = char_range. ch ;
101
+ alt c {
102
+ '+' {
103
+ pos = char_range. next ;
104
+ }
105
+ '-' {
106
+ pos = char_range. next ;
107
+ neg_exponent = true ;
108
+ }
109
+ _ { }
110
+ }
111
+ while ( pos < len) {
112
+ let char_range = str:: char_range_at ( num, pos) ;
113
+ c = char_range. ch ;
114
+ pos = char_range. next ;
115
+ alt c {
116
+ '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' {
117
+ exponent *= 10 u;
118
+ exponent += ( ( c as uint ) - ( '0' as uint ) ) ;
119
+ }
120
+ _ {
121
+ break;
122
+ }
123
+ }
124
+ }
125
+ let multiplier = pow_uint_to_uint_as_float ( 10 u, exponent) ;
126
+ //Note: not [int::pow], otherwise, we'll quickly
127
+ //end up with a nice overflow
128
+ if neg_exponent {
129
+ total = total / multiplier;
130
+ } else {
131
+ total = total * multiplier;
132
+ }
133
+ }
134
+ }
135
+
136
+ if ( pos < len) {
137
+ ret NaN ( ) ;
138
+ } else {
139
+ if ( neg) {
140
+ total *= -1 f;
141
+ }
142
+ ret total;
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Arithmetics
148
+ */
149
+
150
+ /**
151
+ * Compute the exponentiation of an integer by another integer as a float.
152
+ *
153
+ *
154
+ * @param x The base.
155
+ * @param pow The exponent.
156
+ * @return [NaN] of both [x] and [pow] are [0u], otherwise [x^pow].
157
+ */
158
+ fn pow_uint_to_uint_as_float ( x : uint , pow : uint ) -> float {
159
+ if x == 0 u {
160
+ if pow == 0 u {
161
+ ret NaN ( ) ;
162
+ }
163
+ ret 0. ;
164
+ }
165
+ let my_pow = pow;
166
+ let total = 1 f;
167
+ let multiplier = x as float ;
168
+ while ( my_pow > 0 u) {
169
+ if my_pow % 2 u == 1 u {
170
+ total = total * multiplier;
171
+ }
172
+ my_pow /= 2 u;
173
+ multiplier *= multiplier;
174
+ }
175
+ ret total;
176
+ }
177
+
178
+
179
+ /**
180
+ * Constants
181
+ */
182
+
183
+ //TODO: Once this is possible, replace the body of these functions
184
+ //by an actual constant.
185
+
186
+ fn NaN ( ) -> float {
187
+ ret 0. /0. ;
188
+ }
189
+
190
+ fn infinity ( ) -> float {
191
+ ret 1. /0. ;
192
+ }
193
+
194
+ fn neg_infinity ( ) -> float {
195
+ ret -1. /0. ;
33
196
}
34
197
35
198
//
0 commit comments