1
1
use crate :: { Category , ExpInt , IEK_INF , IEK_NAN , IEK_ZERO } ;
2
2
use crate :: { Float , FloatConvert , ParseError , Round , Status , StatusAnd } ;
3
3
4
- use alloc:: vec:: Vec ;
5
4
use core:: cmp:: { self , Ordering } ;
6
5
use core:: convert:: TryFrom ;
7
6
use core:: fmt:: { self , Write } ;
@@ -34,6 +33,21 @@ fn limbs_for_bits(bits: usize) -> usize {
34
33
( bits + LIMB_BITS - 1 ) / LIMB_BITS
35
34
}
36
35
36
+ /// Growable `[Limb]` (i.e. heap-allocated and typically `Vec`/`SmallVec`/etc.),
37
+ /// used only by algorithms that may require dynamically arbitrary precision,
38
+ /// i.e. conversions from/to decimal strings.
39
+ ///
40
+ /// Note: the specific type was chosen by starting with `SmallVec<[_; 1]>` and
41
+ /// increasing the inline length as long as benchmarks were showing improvements,
42
+ /// or at least the `Double::from_str` ones, which roughly had these behaviors:
43
+ /// * `Vec<_>` -> `SmallVec<[_; 1]>`: ~15% speedup, but only for shorter inputs
44
+ /// * `SmallVec<[_; 1]>` -> `SmallVec<[_; 2]>`: ~10% speedup for longer inputs
45
+ /// * `SmallVec<[_; 2]>` -> `SmallVec<[_; 3]>`: noise and/or diminishing returns
46
+ ///
47
+ /// Note: the choice of type described above, and the factors in its decision,
48
+ /// are specific to `Limb` being `u128`, so if `Limb` changes, this should too.
49
+ type DynPrecisionLimbVec = smallvec:: SmallVec < [ Limb ; 2 ] > ;
50
+
37
51
/// Enum that represents what fraction of the LSB truncated bits of an fp number
38
52
/// represent.
39
53
///
@@ -382,7 +396,7 @@ impl<S: Semantics> fmt::Display for IeeeFloat<S> {
382
396
383
397
// Decompose the number into an APInt and an exponent.
384
398
let mut exp = self . exp - ( S :: PRECISION as ExpInt - 1 ) ;
385
- let mut sig = vec ! [ self . sig[ 0 ] ] ;
399
+ let mut sig: DynPrecisionLimbVec = [ self . sig [ 0 ] ] . into_iter ( ) . collect ( ) ;
386
400
387
401
// Ignore trailing binary zeros.
388
402
let trailing_zeros = sig[ 0 ] . trailing_zeros ( ) ;
@@ -405,9 +419,9 @@ impl<S: Semantics> fmt::Display for IeeeFloat<S> {
405
419
406
420
// Multiply significand by 5^e.
407
421
// N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8)
408
- let mut sig_scratch = vec ! [ ] ;
409
- let mut p5 = vec ! [ ] ;
410
- let mut p5_scratch = vec ! [ ] ;
422
+ let mut sig_scratch = DynPrecisionLimbVec :: new ( ) ;
423
+ let mut p5 = DynPrecisionLimbVec :: new ( ) ;
424
+ let mut p5_scratch = DynPrecisionLimbVec :: new ( ) ;
411
425
while texp != 0 {
412
426
if p5. is_empty ( ) {
413
427
p5. push ( 5 ) ;
@@ -432,7 +446,7 @@ impl<S: Semantics> fmt::Display for IeeeFloat<S> {
432
446
}
433
447
434
448
// Fill the buffer.
435
- let mut buffer = vec ! [ ] ;
449
+ let mut buffer = smallvec :: SmallVec :: < [ u8 ; 64 ] > :: new ( ) ;
436
450
437
451
// Ignore digits from the significand until it is no more
438
452
// precise than is required for the desired precision.
@@ -1911,7 +1925,7 @@ impl<S: Semantics> IeeeFloat<S> {
1911
1925
// to hold the full significand, and an extra limb required by
1912
1926
// tcMultiplyPart.
1913
1927
let max_limbs = limbs_for_bits ( 1 + 196 * significand_digits / 59 ) ;
1914
- let mut dec_sig = Vec :: with_capacity ( max_limbs) ;
1928
+ let mut dec_sig = DynPrecisionLimbVec :: with_capacity ( max_limbs) ;
1915
1929
1916
1930
// Convert to binary efficiently - we do almost all multiplication
1917
1931
// in a Limb. When this would overflow do we do a single
@@ -1970,11 +1984,11 @@ impl<S: Semantics> IeeeFloat<S> {
1970
1984
1971
1985
const FIRST_EIGHT_POWERS : [ Limb ; 8 ] = [ 1 , 5 , 25 , 125 , 625 , 3125 , 15625 , 78125 ] ;
1972
1986
1973
- let mut p5_scratch = vec ! [ ] ;
1974
- let mut p5 = vec ! [ FIRST_EIGHT_POWERS [ 4 ] ] ;
1987
+ let mut p5_scratch = DynPrecisionLimbVec :: new ( ) ;
1988
+ let mut p5: DynPrecisionLimbVec = [ FIRST_EIGHT_POWERS [ 4 ] ] . into_iter ( ) . collect ( ) ;
1975
1989
1976
- let mut r_scratch = vec ! [ ] ;
1977
- let mut r = vec ! [ FIRST_EIGHT_POWERS [ power & 7 ] ] ;
1990
+ let mut r_scratch = DynPrecisionLimbVec :: new ( ) ;
1991
+ let mut r: DynPrecisionLimbVec = [ FIRST_EIGHT_POWERS [ power & 7 ] ] . into_iter ( ) . collect ( ) ;
1978
1992
power >>= 3 ;
1979
1993
1980
1994
while power > 0 {
@@ -2007,7 +2021,7 @@ impl<S: Semantics> IeeeFloat<S> {
2007
2021
let calc_precision = ( LIMB_BITS << attempt) - 1 ;
2008
2022
attempt += 1 ;
2009
2023
2010
- let calc_normal_from_limbs = |sig : & mut Vec < Limb > , limbs : & [ Limb ] | -> StatusAnd < ExpInt > {
2024
+ let calc_normal_from_limbs = |sig : & mut DynPrecisionLimbVec , limbs : & [ Limb ] | -> StatusAnd < ExpInt > {
2011
2025
sig. resize ( limbs_for_bits ( calc_precision) , 0 ) ;
2012
2026
let ( mut loss, mut exp) = sig:: from_limbs ( sig, limbs, calc_precision) ;
2013
2027
0 commit comments