]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | //! Utility functions for bignums that don't make too much sense to turn into methods. |
2 | ||
3 | // FIXME This module's name is a bit unfortunate, since other modules also import `core::num`. | |
4 | ||
e9174d1e | 5 | use cmp::Ordering::{self, Less, Equal, Greater}; |
e9174d1e | 6 | |
b039eaaf | 7 | pub use num::bignum::Big32x40 as Big; |
e9174d1e SL |
8 | |
9 | /// Test whether truncating all bits less significant than `ones_place` introduces | |
10 | /// a relative error less, equal, or greater than 0.5 ULP. | |
11 | pub fn compare_with_half_ulp(f: &Big, ones_place: usize) -> Ordering { | |
12 | if ones_place == 0 { | |
13 | return Less; | |
14 | } | |
15 | let half_bit = ones_place - 1; | |
16 | if f.get_bit(half_bit) == 0 { | |
17 | // < 0.5 ULP | |
18 | return Less; | |
19 | } | |
20 | // If all remaining bits are zero, it's = 0.5 ULP, otherwise > 0.5 | |
21 | // If there are no more bits (half_bit == 0), the below also correctly returns Equal. | |
22 | for i in 0..half_bit { | |
23 | if f.get_bit(i) == 1 { | |
24 | return Greater; | |
25 | } | |
26 | } | |
27 | Equal | |
28 | } | |
29 | ||
9fa01778 | 30 | /// Converts an ASCII string containing only decimal digits to a `u64`. |
e9174d1e SL |
31 | /// |
32 | /// Does not perform checks for overflow or invalid characters, so if the caller is not careful, | |
33 | /// the result is bogus and can panic (though it won't be `unsafe`). Additionally, empty strings | |
34 | /// are treated as zero. This function exists because | |
35 | /// | |
36 | /// 1. using `FromStr` on `&[u8]` requires `from_utf8_unchecked`, which is bad, and | |
37 | /// 2. piecing together the results of `integral.parse()` and `fractional.parse()` is | |
38 | /// more complicated than this entire function. | |
39 | pub fn from_str_unchecked<'a, T>(bytes: T) -> u64 where T : IntoIterator<Item=&'a u8> { | |
40 | let mut result = 0; | |
41 | for &c in bytes { | |
42 | result = result * 10 + (c - b'0') as u64; | |
43 | } | |
44 | result | |
45 | } | |
46 | ||
9fa01778 | 47 | /// Converts a string of ASCII digits into a bignum. |
e9174d1e SL |
48 | /// |
49 | /// Like `from_str_unchecked`, this function relies on the parser to weed out non-digits. | |
50 | pub fn digits_to_big(integral: &[u8], fractional: &[u8]) -> Big { | |
51 | let mut f = Big::from_small(0); | |
52 | for &c in integral.iter().chain(fractional) { | |
53 | let n = (c - b'0') as u32; | |
54 | f.mul_small(10); | |
55 | f.add_small(n); | |
56 | } | |
57 | f | |
58 | } | |
59 | ||
60 | /// Unwraps a bignum into a 64 bit integer. Panics if the number is too large. | |
61 | pub fn to_u64(x: &Big) -> u64 { | |
62 | assert!(x.bit_length() < 64); | |
63 | let d = x.digits(); | |
64 | if d.len() < 2 { | |
65 | d[0] as u64 | |
66 | } else { | |
67 | (d[1] as u64) << 32 | d[0] as u64 | |
68 | } | |
69 | } | |
70 | ||
71 | ||
9fa01778 | 72 | /// Extracts a range of bits. |
e9174d1e SL |
73 | |
74 | /// Index 0 is the least significant bit and the range is half-open as usual. | |
75 | /// Panics if asked to extract more bits than fit into the return type. | |
76 | pub fn get_bits(x: &Big, start: usize, end: usize) -> u64 { | |
77 | assert!(end - start <= 64); | |
78 | let mut result: u64 = 0; | |
79 | for i in (start..end).rev() { | |
80 | result = result << 1 | x.get_bit(i) as u64; | |
81 | } | |
82 | result | |
83 | } |