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
//! [![github]](https://github.com/dtolnay/precise) [![crates-io]](https://crates.io/crates/precise) [![docs-rs]](https://docs.rs/precise)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
//!
//! <br>
//!
//! Decimal representation of the single rational number whose value is
//! mathematically equal to the input float.
//!
//! Note that this is almost never an appropriate way to print user-facing
//! values. For that, use the [ryu] crate instead.
//!
//! [ryu]: https://github.com/dtolnay/ryu
//!
//! # Example
//!
//! ```
//! fn main() {
//!     // 0.1000000000000000055511151231257827021181583404541015625
//!     println!("{}", precise::to_string(0.1));
//! }
//! ```

use num_bigint::BigUint;
use num_traits::Pow;

pub fn to_string(n: f64) -> String {
    if n.is_nan() {
        return "NaN".to_owned();
    }

    if n.is_infinite() {
        if n.is_sign_positive() {
            return "inf".to_owned();
        } else {
            return "-inf".to_owned();
        }
    }

    let bits = n.to_bits();
    let is_negative = (bits & 0x8000_0000_0000_0000) != 0;
    let biased_exponent = (bits & 0x7FF0_0000_0000_0000) >> 52;
    let significand = (bits & 0x000F_FFFF_FFFF_FFFF) + (1 << 52);

    // value
    //   = significand * 2^(biased_exponent - 1075)
    //   = significand * 2^biased_exponent * 5^1075 / 10^1075
    let significand = BigUint::from(significand);
    let two = BigUint::from(2u8);
    let five = BigUint::from(5u8);
    let numerator = significand * two.pow(biased_exponent) * five.pow(1075u16);

    let mut repr = numerator.to_string();
    let more_zeros = 1076usize.saturating_sub(repr.len());
    let leading_zeros = "0".repeat(more_zeros);
    repr = leading_zeros + &repr;

    let point = repr.len() - 1075;
    repr = format!("{}.{}", &repr[..point], &repr[point..]);
    repr = repr.trim_end_matches('0').to_owned();
    if repr.ends_with('.') {
        repr.push('0');
    }

    if is_negative {
        repr.insert(0, '-');
    }

    repr
}