nanvm_lib/vm/bigint/
to_f64.rs1use super::BigInt;
2use crate::{
3 common::sized_index::SizedIndex,
4 vm::{IVm, Number},
5};
6
7impl<A: IVm> BigInt<A> {
8 pub fn to_number(&self) -> Number {
17 let length = self.length();
18 let (significand, words_below, sticky) = match length {
19 0 => (0, 0, false),
20 1 => (u128::from(self[0]), 0, false),
21 _ => (
22 (u128::from(self[length - 1]) << 64) | u128::from(self[length - 2]),
23 length - 2,
24 (0..length - 2).any(|i| self[i] != 0),
25 ),
26 };
27 let exponent =
28 i32::try_from(64 * words_below).expect("a BigInt's words are far under 2^31 bits");
29 Number::compose(self.sign(), significand, exponent, sticky)
30 .expect("`sticky` is set only under a nonzero top word: over 64 significant bits")
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use crate::{
37 naive::Naive,
38 sign::Sign,
39 vm::{BigInt, Number},
40 };
41
42 fn n(sign: Sign, words: &[u64]) -> f64 {
43 f64::from(BigInt::<Naive>::normalize_new(sign, words.iter().copied()).to_number())
44 }
45
46 fn pos(words: &[u64]) -> f64 {
47 n(Sign::Positive, words)
48 }
49
50 #[test]
51 fn small() {
52 assert_eq!(pos(&[]), 0.0);
53 assert!(pos(&[]).is_sign_positive());
54 assert!(n(Sign::Negative, &[]).is_sign_positive());
55 assert_eq!(pos(&[1]), 1.0);
56 assert_eq!(n(Sign::Negative, &[1]), -1.0);
57 assert_eq!(pos(&[u64::MAX]), u64::MAX as f64);
58 }
59
60 #[test]
61 fn two_to_the_53() {
62 assert_eq!(pos(&[1 << 53]), 9_007_199_254_740_992.0);
63 assert_eq!(pos(&[(1 << 53) + 1]), 9_007_199_254_740_992.0);
65 assert_eq!(pos(&[(1 << 53) + 3]), 9_007_199_254_740_996.0);
67 }
68
69 #[test]
70 fn sticky_bits_break_a_tie() {
71 let two_64 = 18_446_744_073_709_551_616.0;
74 assert_eq!(pos(&[1 << 11, 1]), two_64);
75 assert_eq!(pos(&[(1 << 11) + 1, 1]), two_64 + 4_096.0);
76 assert_eq!(pos(&[1, 1 << 11, 1]), two_64 * two_64 + two_64 * 4_096.0);
78 assert_eq!(pos(&[0, 1 << 11, 1]), two_64 * two_64);
79 }
80
81 #[test]
82 fn several_words() {
83 assert_eq!(
85 pos(&[0xC373_E0EE_4E3F_0AD2, 0x1_8EE9_0FF6]),
86 123_456_789_012_345_678_901_234_567_890.0
87 );
88 assert_eq!(pos(&[0, 1]), 18_446_744_073_709_551_616.0);
89 assert_eq!(
90 pos(&[0, 0, 1]),
91 340_282_366_920_938_463_463_374_607_431_768_211_456.0
92 );
93 }
94
95 #[test]
96 fn range() {
97 let mut words = vec![0u64; 16];
99 words[15] = 1 << 63;
100 assert_eq!(pos(&words), 2f64.powi(1_023));
101 let all = vec![u64::MAX; 16];
103 assert_eq!(pos(&all), f64::INFINITY);
104 assert_eq!(n(Sign::Negative, &all), f64::NEG_INFINITY);
105 let mut words = vec![0u64; 16];
107 words[15] = u64::MAX << 11;
108 assert_eq!(pos(&words), f64::MAX);
109 assert_eq!(pos(&vec![1u64; 40]), f64::INFINITY);
111 }
112
113 #[test]
114 fn never_nan() {
115 let v: Number = BigInt::<Naive>::normalize_new(Sign::Positive, [0u64; 3]).to_number();
116 assert_eq!(f64::from(v), 0.0);
117 }
118}