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
//! 将浮点数表示为有效数字和指数。

use crate::num::dec2flt::float::RawFloat;
use crate::num::dec2flt::fpu::set_precision;

#[rustfmt::skip]
const INT_POW10: [u64; 16] = [
    1,
    10,
    100,
    1000,
    10000,
    100000,
    1000000,
    10000000,
    100000000,
    1000000000,
    10000000000,
    100000000000,
    1000000000000,
    10000000000000,
    100000000000000,
    1000000000000000,
];

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Number {
    pub exponent: i64,
    pub mantissa: u64,
    pub negative: bool,
    pub many_digits: bool,
}

impl Number {
    /// 检测是否可以从原生浮点数准确地重建浮点数。
    #[inline]
    fn is_fast_path<F: RawFloat>(&self) -> bool {
        F::MIN_EXPONENT_FAST_PATH <= self.exponent
            && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
            && self.mantissa <= F::MAX_MANTISSA_FAST_PATH
            && !self.many_digits
    }

    /// 使用机器大小的整数和浮点数的快速路径算法。
    ///
    /// 这被提取到一个单独的函数中,以便可以在创建一个 Decimal 之前尝试它。
    /// 这只适用于尾数和指数都可以精确表示为机器浮点数的情况,因为 IEE-754 保证不会发生舍入。
    ///
    ///
    /// 有一个例外:伪装的快速路径情况,我们可以将 10 的幂从指数转移到有效数字。
    ///
    ///
    pub fn try_fast_path<F: RawFloat>(&self) -> Option<F> {
        // 快速路径至关重要地取决于将算术四舍五入到正确的位数,而无需任何中间舍入。
        // 在 x86 (不带 SSE 或 SSE2) 上,这需要更改 x87 FPU 栈的精度,以便直接将其舍入为 64/32 位。
        // `set_precision` 函数负责在需要通过更改 ^ 状态 (例如 x87 FPU 的控制字) 进行设置的体系结构上设置精度。
        //
        //
        let _cw = set_precision::<F>();

        if self.is_fast_path::<F>() {
            let mut value = if self.exponent <= F::MAX_EXPONENT_FAST_PATH {
                // 正常快速路径
                let value = F::from_u64(self.mantissa);
                if self.exponent < 0 {
                    value / F::pow10_fast_path((-self.exponent) as _)
                } else {
                    value * F::pow10_fast_path(self.exponent as _)
                }
            } else {
                // 伪装的快速路径
                let shift = self.exponent - F::MAX_EXPONENT_FAST_PATH;
                let mantissa = self.mantissa.checked_mul(INT_POW10[shift as usize])?;
                if mantissa > F::MAX_MANTISSA_FAST_PATH {
                    return None;
                }
                F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATH as _)
            };
            if self.negative {
                value = -value;
            }
            Some(value)
        } else {
            None
        }
    }
}