1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
use util::*;
cfg_if! {
if #[cfg(feature = "correct")] {
use super::algorithm::correct as algorithm;
} else {
use super::algorithm::incorrect as algorithm;
}} trait StringToFloat: Float {
fn default<'a>(radix: u32, bytes: &'a [u8], sign: Sign) -> (Self, &'a [u8]);
fn lossy<'a>(radix: u32, bytes: &'a [u8], sign: Sign) -> (Self, &'a [u8]);
}
impl StringToFloat for f32 {
#[inline]
fn default<'a>(radix: u32, bytes: &'a [u8], sign: Sign) -> (f32, &'a [u8]) {
algorithm::atof(radix, bytes, sign)
}
#[inline]
fn lossy<'a>(radix: u32, bytes: &'a [u8], sign: Sign) -> (f32, &'a [u8]) {
algorithm::atof_lossy(radix, bytes, sign)
}
}
impl StringToFloat for f64 {
#[inline]
fn default<'a>(radix: u32, bytes: &'a [u8], sign: Sign) -> (f64, &'a [u8]) {
algorithm::atod(radix, bytes, sign)
}
#[inline]
fn lossy<'a>(radix: u32, bytes: &'a [u8], sign: Sign) -> (f64, &'a [u8]) {
algorithm::atod_lossy(radix, bytes, sign)
}
}
#[inline]
fn is_nan(bytes: &[u8]) -> bool {
unsafe {
case_insensitive_starts_with_slice(bytes, NAN_STRING)
}
}
#[inline]
fn is_inf(bytes: &[u8]) -> bool {
unsafe {
case_insensitive_starts_with_slice(bytes, INF_STRING)
}
}
#[inline]
fn is_infinity(bytes: &[u8]) -> bool {
unsafe {
case_insensitive_starts_with_slice(bytes, INFINITY_STRING)
}
}
#[inline]
fn is_zero(bytes: &[u8]) -> bool {
match bytes.len() {
1 => equal_to_slice(bytes, b"0"),
3 => equal_to_slice(bytes, b"0.0"),
_ => false,
}
}
#[inline]
fn filter_special<'a, F: StringToFloat>(radix: u32, bytes: &'a [u8], lossy: bool, sign: Sign)
-> (F, &'a [u8])
{
unsafe {
if is_zero(bytes) {
(F::ZERO, &bytes[bytes.len()..])
} else if is_infinity(bytes) {
(F::INFINITY, &bytes[INFINITY_STRING.len()..])
} else if is_inf(bytes) {
(F::INFINITY, &bytes[INF_STRING.len()..])
} else if is_nan(bytes) {
(F::NAN, &bytes[NAN_STRING.len()..])
} else if bytes.len() == 1 && bytes[0] == b'.' {
(F::ZERO, bytes)
} else if lossy {
F::lossy(radix, bytes, sign)
} else {
F::default(radix, bytes, sign)
}
}
}
#[inline]
fn filter_sign<'a, F: StringToFloat>(radix: u32, bytes: &'a [u8], lossy: bool)
-> (F, Sign, &'a [u8])
{
let len = bytes.len();
let (sign_bytes, sign) = match bytes.get(0) {
Some(b'+') => (1, Sign::Positive),
Some(b'-') => (1, Sign::Negative),
_ => (0, Sign::Positive),
};
if len > sign_bytes {
let (value, slc) = filter_special::<F>(radix, &bytes[sign_bytes..], lossy, sign);
(value, sign, slc)
} else {
(F::ZERO, sign, bytes)
}
}
#[inline]
fn atof<F: StringToFloat>(radix: u32, bytes: &[u8], lossy: bool)
-> (F, usize)
{
let (value, sign, slc) = filter_sign::<F>(radix, bytes, lossy);
let processed = distance(bytes.as_ptr(), slc.as_ptr());
match sign {
Sign::Negative => (-value, processed),
Sign::Positive => (value, processed),
}
}
macro_rules! wrap {
($name:ident, $f:tt, $lossy:expr) => (
#[inline]
fn $name(radix: u8, bytes: &[u8])
-> ($f, usize, bool)
{
let (value, len) = atof::<$f>(radix.into(), bytes, $lossy);
(value, len, false)
}
)
}
wrap!(atof32_impl, f32, false);
wrap!(atof64_impl, f64, false);
wrap!(atof32_lossy_impl, f32, true);
wrap!(atof64_lossy_impl, f64, true);
generate_from_range_api!(atof32_range, atof32_radix_range, f32, atof32_impl);
generate_from_range_api!(atof64_range, atof64_radix_range, f64, atof64_impl);
generate_from_range_api!(atof32_lossy_range, atof32_lossy_radix_range, f32, atof32_lossy_impl);
generate_from_range_api!(atof64_lossy_range, atof64_lossy_radix_range, f64, atof64_lossy_impl);
generate_try_from_range_api!(try_atof32_range, try_atof32_radix_range, f32, atof32_impl);
generate_try_from_range_api!(try_atof64_range, try_atof64_radix_range, f64, atof64_impl);
generate_try_from_range_api!(try_atof32_lossy_range, try_atof32_lossy_radix_range, f32, atof32_lossy_impl);
generate_try_from_range_api!(try_atof64_lossy_range, try_atof64_lossy_radix_range, f64, atof64_lossy_impl);
generate_from_slice_api!(atof32_slice, atof32_radix_slice, f32, atof32_impl);
generate_from_slice_api!(atof64_slice, atof64_radix_slice, f64, atof64_impl);
generate_from_slice_api!(atof32_lossy_slice, atof32_lossy_radix_slice, f32, atof32_lossy_impl);
generate_from_slice_api!(atof64_lossy_slice, atof64_lossy_radix_slice, f64, atof64_lossy_impl);
generate_try_from_slice_api!(try_atof32_slice, try_atof32_radix_slice, f32, atof32_impl);
generate_try_from_slice_api!(try_atof64_slice, try_atof64_radix_slice, f64, atof64_impl);
generate_try_from_slice_api!(try_atof32_lossy_slice, try_atof32_lossy_radix_slice, f32, atof32_lossy_impl);
generate_try_from_slice_api!(try_atof64_lossy_slice, try_atof64_lossy_radix_slice, f64, atof64_lossy_impl);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn atof32_base10_test() {
assert_f32_eq!(0.0, atof32_slice(b"0"));
assert_f32_eq!(1.0, atof32_slice(b"1"));
assert_f32_eq!(12.0, atof32_slice(b"12"));
assert_f32_eq!(123.0, atof32_slice(b"123"));
assert_f32_eq!(1234.0, atof32_slice(b"1234"));
assert_f32_eq!(12345.0, atof32_slice(b"12345"));
assert_f32_eq!(123456.0, atof32_slice(b"123456"));
assert_f32_eq!(1234567.0, atof32_slice(b"1234567"));
assert_f32_eq!(12345678.0, atof32_slice(b"12345678"));
assert_f64_eq!(1.0, atof32_slice(b"1."));
assert_f64_eq!(12.0, atof32_slice(b"12."));
assert_f64_eq!(1234567.0, atof32_slice(b"1234567."));
assert_f32_eq!(123.1, atof32_slice(b"123.1"));
assert_f32_eq!(123.12, atof32_slice(b"123.12"));
assert_f32_eq!(123.123, atof32_slice(b"123.123"));
assert_f32_eq!(123.1234, atof32_slice(b"123.1234"));
assert_f32_eq!(123.12345, atof32_slice(b"123.12345"));
assert_f32_eq!(123456790.0, atof32_slice(b"123456789"));
assert_f32_eq!(123456790.0, atof32_slice(b"123456789.1"));
assert_f32_eq!(123456790.0, atof32_slice(b"123456789.12"));
assert_f32_eq!(123456790.0, atof32_slice(b"123456789.123"));
assert_f32_eq!(123456790.0, atof32_slice(b"123456789.1234"));
assert_f32_eq!(123456790.0, atof32_slice(b"123456789.12345"));
assert_f32_eq!(123456789.12345, atof32_slice(b"1.2345678912345e8"));
assert_f32_eq!(123450000.0, atof32_slice(b"1.2345e+8"));
assert_f32_eq!(1.2345e+11, atof32_slice(b"1.2345e+11"));
assert_f32_eq!(1.2345e+11, atof32_slice(b"123450000000"));
assert_f32_eq!(1.2345e+38, atof32_slice(b"1.2345e+38"));
assert_f32_eq!(1.2345e+38, atof32_slice(b"123450000000000000000000000000000000000"));
assert_f32_eq!(1.2345e-8, atof32_slice(b"1.2345e-8"));
assert_f32_eq!(1.2345e-8, atof32_slice(b"0.000000012345"));
assert_f32_eq!(1.2345e-38, atof32_slice(b"1.2345e-38"));
assert_f32_eq!(1.2345e-38, atof32_slice(b"0.000000000000000000000000000000000000012345"));
assert!(atof32_slice(b"NaN").is_nan());
assert!(atof32_slice(b"nan").is_nan());
assert!(atof32_slice(b"NAN").is_nan());
assert!(atof32_slice(b"inf").is_infinite());
assert!(atof32_slice(b"INF").is_infinite());
assert!(atof32_slice(b"+inf").is_infinite());
assert!(atof32_slice(b"-inf").is_infinite());
}
#[cfg(feature = "radix")]
#[test]
fn atof32_basen_test() {
assert_f32_eq!(1234.0, atof32_radix_slice(36, b"YA"));
assert_f32_eq!(1234.0, atof32_lossy_radix_slice(36, b"YA"));
}
#[test]
fn atof64_base10_test() {
assert_f64_eq!(0.0, atof64_slice(b"0"));
assert_f64_eq!(1.0, atof64_slice(b"1"));
assert_f64_eq!(12.0, atof64_slice(b"12"));
assert_f64_eq!(123.0, atof64_slice(b"123"));
assert_f64_eq!(1234.0, atof64_slice(b"1234"));
assert_f64_eq!(12345.0, atof64_slice(b"12345"));
assert_f64_eq!(123456.0, atof64_slice(b"123456"));
assert_f64_eq!(1234567.0, atof64_slice(b"1234567"));
assert_f64_eq!(12345678.0, atof64_slice(b"12345678"));
assert_f64_eq!(1.0, atof64_slice(b"1."));
assert_f64_eq!(12.0, atof64_slice(b"12."));
assert_f64_eq!(1234567.0, atof64_slice(b"1234567."));
assert_f64_eq!(123456789.0, atof64_slice(b"123456789"));
assert_f64_eq!(123456789.1, atof64_slice(b"123456789.1"));
assert_f64_eq!(123456789.12, atof64_slice(b"123456789.12"));
assert_f64_eq!(123456789.123, atof64_slice(b"123456789.123"));
assert_f64_eq!(123456789.1234, atof64_slice(b"123456789.1234"));
assert_f64_eq!(123456789.12345, atof64_slice(b"123456789.12345"));
assert_f64_eq!(123456789.123456, atof64_slice(b"123456789.123456"));
assert_f64_eq!(123456789.1234567, atof64_slice(b"123456789.1234567"));
assert_f64_eq!(123456789.12345678, atof64_slice(b"123456789.12345678"));
assert_f64_eq!(123456789.12345679, atof64_slice(b"123456789.123456789"));
assert_f64_eq!(123456789.12345679, atof64_slice(b"123456789.1234567890"));
assert_f64_eq!(123456789.12345679, atof64_slice(b"123456789.123456789012"));
assert_f64_eq!(123456789.12345679, atof64_slice(b"123456789.1234567890123"));
assert_f64_eq!(123456789.12345679, atof64_slice(b"123456789.12345678901234"));
assert_f64_eq!(123456789.12345, atof64_slice(b"1.2345678912345e8"));
assert_f64_eq!(123450000.0, atof64_slice(b"1.2345e+8"));
assert_f64_eq!(1.2345e+11, atof64_slice(b"123450000000"));
assert_f64_eq!(1.2345e+11, atof64_slice(b"1.2345e+11"));
assert_f64_eq!(1.2345e+38, atof64_slice(b"1.2345e+38"));
assert_f64_eq!(1.2345e+38, atof64_slice(b"123450000000000000000000000000000000000"));
assert_f64_eq!(1.2345e+308, atof64_slice(b"1.2345e+308"));
assert_f64_eq!(1.2345e+308, atof64_slice(b"123450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
assert_f64_eq!(0.000000012345, atof64_slice(b"1.2345e-8"));
assert_f64_eq!(1.2345e-8, atof64_slice(b"0.000000012345"));
assert_f64_eq!(1.2345e-38, atof64_slice(b"1.2345e-38"));
assert_f64_eq!(1.2345e-38, atof64_slice(b"0.000000000000000000000000000000000000012345"));
assert_f64_eq!(1.2345e-308, atof64_slice(b"1.2345e-308"));
assert_eq!(5e-322, atof64_slice(b"5e-322"));
assert_eq!(5e-323, atof64_slice(b"5e-323"));
assert_eq!(5e-324, atof64_slice(b"5e-324"));
assert_f64_eq!(1.2345e-299, atof64_slice(b"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345"), epsilon=1e-314);
assert_f64_eq!(1.2345e-300, atof64_slice(b"0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345"), epsilon=1e-315);
assert_f64_eq!(1.2345e-310, atof64_slice(b"0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345"), epsilon=5e-324);
assert_f64_eq!(1.2345e-320, atof64_slice(b"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345"), epsilon=5e-324);
assert_f64_eq!(1.2345e-321, atof64_slice(b"0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345"), epsilon=5e-324);
assert_f64_eq!(1.24e-322, atof64_slice(b"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000124"), epsilon=5e-324);
assert_eq!(1e-323, atof64_slice(b"0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"));
assert_eq!(5e-324, atof64_slice(b"0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005"));
assert!(atof64_slice(b"NaN").is_nan());
assert!(atof64_slice(b"nan").is_nan());
assert!(atof64_slice(b"NAN").is_nan());
assert!(atof64_slice(b"inf").is_infinite());
assert!(atof64_slice(b"INF").is_infinite());
assert!(atof64_slice(b"+inf").is_infinite());
assert!(atof64_slice(b"-inf").is_infinite());
assert_eq!(0.0, atof64_slice(b"0e"));
assert_eq!(0.0, atof64_slice(b"0.0e"));
assert_eq!(0.0, atof64_slice(b".E"));
assert_eq!(0.0, atof64_slice(b".e"));
assert_eq!(0.0, atof64_slice(b"E2252525225"));
assert_eq!(f64::INFINITY, atof64_slice(b"2E200000000000"));
assert_eq!(ErrorCode::InvalidDigit, try_atof64_slice(b"0e").error.code);
assert_eq!(ErrorCode::InvalidDigit, try_atof64_slice(b".").error.code);
assert_eq!(ErrorCode::InvalidDigit, try_atof64_slice(b"+.").error.code);
assert_eq!(ErrorCode::InvalidDigit, try_atof64_slice(b"-.").error.code);
assert_eq!(ErrorCode::InvalidDigit, try_atof64_slice(b"+").error.code);
assert_eq!(ErrorCode::InvalidDigit, try_atof64_slice(b"-").error.code);
}
#[test]
#[should_panic]
fn limit_test() {
assert_relative_eq!(1.2345e-320, 0.0, epsilon=5e-324);
}
#[cfg(feature = "radix")]
#[test]
fn atof64_basen_test() {
assert_f64_eq!(1234.0, atof64_radix_slice(36, b"YA"));
assert_f64_eq!(1234.0, atof64_lossy_radix_slice(36, b"YA"));
}
#[test]
fn try_atof32_base10_test() {
assert_eq!(invalid_digit_error(0.0, 0), try_atof32_slice(b"."));
assert_eq!(empty_error(0.0), try_atof32_slice(b""));
assert_eq!(success(0.0), try_atof32_slice(b"0.0"));
assert_eq!(invalid_digit_error(1.0, 1), try_atof32_slice(b"1a"));
}
#[test]
fn try_atof64_base10_test() {
assert_eq!(invalid_digit_error(0.0, 0), try_atof64_slice(b"."));
assert_eq!(empty_error(0.0), try_atof64_slice(b""));
assert_eq!(success(0.0), try_atof64_slice(b"0.0"));
assert_eq!(invalid_digit_error(1.0, 1), try_atof64_slice(b"1a"));
}
proptest! {
#[test]
fn f32_invalid_proptest(i in r"[+-]?[0-9]{2}\D?\.\D?[0-9]{2}\D?e[+-]?[0-9]+\D") {
let res = try_atof32_slice(i.as_bytes());
assert_eq!(res.error.code, ErrorCode::InvalidDigit);
}
#[test]
fn f32_double_sign_proptest(i in r"[+-]{2}[0-9]{2}\.[0-9]{2}e[+-]?[0-9]+") {
let res = try_atof32_slice(i.as_bytes());
assert_eq!(res.error.code, ErrorCode::InvalidDigit);
assert!(res.error.index == 0 || res.error.index == 1);
}
#[test]
fn f32_sign_or_dot_only_proptest(i in r"[+-]?\.?") {
let res = try_atof32_slice(i.as_bytes());
if i.is_empty() {
assert_eq!(res.error.code, ErrorCode::Empty);
} else {
assert_eq!(res.error.code, ErrorCode::InvalidDigit);
}
assert!(res.error.index == 0 || res.error.index == 1);
}
#[test]
fn f32_double_exponent_sign_proptest(i in r"[+-]?[0-9]{2}\.[0-9]{2}e[+-]{2}[0-9]+") {
let res = try_atof32_slice(i.as_bytes());
assert_eq!(res.error.code, ErrorCode::InvalidDigit);
}
#[test]
fn f32_missing_exponent_proptest(i in r"[+-]?[0-9]{2}\.[0-9]{2}e[+-]?") {
let res = try_atof32_slice(i.as_bytes());
assert_eq!(res.error.code, ErrorCode::InvalidDigit);
}
#[test]
fn f64_invalid_proptest(i in r"[+-]?[0-9]{2}\D?\.\D?[0-9]{2}\D?e[+-]?[0-9]+\D") {
let res = try_atof64_slice(i.as_bytes());
assert_eq!(res.error.code, ErrorCode::InvalidDigit);
}
#[test]
fn f64_double_sign_proptest(i in r"[+-]{2}[0-9]{2}\.[0-9]{2}e[+-]?[0-9]+") {
let res = try_atof64_slice(i.as_bytes());
assert_eq!(res.error.code, ErrorCode::InvalidDigit);
assert!(res.error.index == 0 || res.error.index == 1);
}
#[test]
fn f64_sign_or_dot_only_proptest(i in r"[+-]?\.?") {
let res = try_atof64_slice(i.as_bytes());
if i.is_empty() {
assert_eq!(res.error.code, ErrorCode::Empty);
} else {
assert_eq!(res.error.code, ErrorCode::InvalidDigit);
}
assert!(res.error.index == 0 || res.error.index == 1);
}
#[test]
fn f64_double_exponent_sign_proptest(i in r"[+-]?[0-9]{2}\.[0-9]{2}e[+-]{2}[0-9]+") {
let res = try_atof64_slice(i.as_bytes());
assert_eq!(res.error.code, ErrorCode::InvalidDigit);
}
#[test]
fn f64_missing_exponent_proptest(i in r"[+-]?[0-9]{2}\.[0-9]{2}e[+-]?") {
let res = try_atof64_slice(i.as_bytes());
assert_eq!(res.error.code, ErrorCode::InvalidDigit);
}
}
}