1use std::{cmp::Ordering, ops::Deref};
2
3use crate::{
4 js::js_bigint::{
5 div_mod, from_u64, is_zero, mul, pow_u64, shl, shl_on_u64, shr_on_u64, zero, JsBigint,
6 JsBigintMutRef, Sign,
7 },
8 mem::manager::Manager,
9};
10
11#[derive(Debug)]
12pub struct BigFloat<const BASE: u32, M: Manager> {
13 pub manager: M,
14 pub significand: JsBigintMutRef<M::Dealloc>,
15 pub sign: Sign,
16 pub exp: i64,
17 pub non_zero_reminder: bool,
18}
19
20pub fn float_zero<const BASE: u32, M: Manager>(manager: M) -> BigFloat<BASE, M> {
21 BigFloat {
22 manager,
23 significand: zero(manager),
24 sign: Sign::Positive,
25 exp: 0,
26 non_zero_reminder: false,
27 }
28}
29
30impl<const BASE: u32, M: Manager> BigFloat<BASE, M> {
31 fn increase_significand(&mut self, precision: u64) {
32 if is_zero(self.significand.deref()) {
33 return;
34 }
35
36 let min_significand = shl(
37 self.manager,
38 from_u64(self.manager, Sign::Positive, 1).deref(),
39 from_u64(self.manager, Sign::Positive, precision).deref(),
40 );
41 self.increase_significand_to(min_significand.deref());
42 }
43
44 fn increase_significand_to(&mut self, min_significand: &JsBigint) {
45 if is_zero(self.significand.deref()) {
46 return;
47 }
48
49 loop {
50 match self.significand.deref().compare(min_significand) {
51 Ordering::Greater | Ordering::Equal => return,
52 _ => {}
53 }
54 self.significand = shl_on_u64(self.manager, self.significand.deref(), 1);
55 self.exp -= 1;
56 }
57 }
58
59 fn decrease_significand(&mut self, precision: u64) {
60 if is_zero(self.significand.deref()) {
61 return;
62 }
63
64 let max_significand = shl(
65 self.manager,
66 from_u64(self.manager, Sign::Positive, 1).deref(),
67 from_u64(self.manager, Sign::Positive, precision).deref(),
68 );
69 loop {
70 if self.significand.deref().compare(max_significand.deref()) == Ordering::Less {
71 break;
72 }
73 let last_bit = self.significand.get_last_bit();
74 if last_bit == 1 {
75 self.non_zero_reminder = true;
76 }
77 self.significand = shr_on_u64(self.manager, self.significand.deref(), 1);
78 self.exp += 1;
79 }
80 }
81}
82
83impl<M: Manager> BigFloat<10, M> {
84 pub fn to_bin(self, precision: u8) -> BigFloat<2, M> {
85 if is_zero(self.significand.deref()) {
86 return float_zero(self.manager);
87 }
88
89 if self.exp == 0 {
90 let mut result: BigFloat<2, M> = BigFloat {
91 manager: self.manager,
92 significand: self.significand,
93 sign: self.sign,
94 exp: self.exp,
95 non_zero_reminder: self.non_zero_reminder,
96 };
97 result.increase_significand(precision as u64);
98 result.decrease_significand(precision as u64);
99 return result;
100 }
101
102 let five = from_u64(self.manager, Sign::Positive, 5);
103 if self.exp > 0 {
104 let new_sign = mul(
105 self.manager,
106 self.significand.deref(),
107 pow_u64(self.manager, five.deref(), self.exp as u64).deref(),
108 );
109 let mut result: BigFloat<2, M> = BigFloat {
110 manager: self.manager,
111 significand: new_sign,
112 sign: self.sign,
113 exp: self.exp,
114 non_zero_reminder: self.non_zero_reminder,
115 };
116 result.increase_significand(precision as u64);
117 result.decrease_significand(precision as u64);
118 return result;
119 }
120
121 let p = pow_u64(self.manager, five.deref(), -self.exp as u64);
122 let mut bf10: BigFloat<10, M> = BigFloat {
123 manager: self.manager,
124 significand: self.significand,
125 sign: self.sign,
126 exp: self.exp,
127 non_zero_reminder: self.non_zero_reminder,
128 };
129 let min_significand = shl(
130 self.manager,
131 from_u64(self.manager, Sign::Positive, 1).deref(),
132 from_u64(self.manager, Sign::Positive, precision as u64).deref(),
133 );
134 bf10.increase_significand_to(
135 (mul(self.manager, p.deref(), min_significand.deref())).deref(),
136 );
137
138 let (q, r) = div_mod(self.manager, bf10.significand.deref(), p.deref());
139 let mut result: BigFloat<2, M> = BigFloat {
140 manager: self.manager,
141 significand: q,
142 sign: self.sign,
143 exp: bf10.exp,
144 non_zero_reminder: self.non_zero_reminder || !is_zero(r.deref()),
145 };
146 result.decrease_significand(precision as u64);
147 result
148 }
149}
150
151impl<M: Manager> BigFloat<2, M> {
152 fn get_frac_round(self) -> u64 {
153 let mut last_bit = self.significand.get_last_bit();
154 let mut frac = self.significand.items()[0] >> 1;
155
156 if last_bit == 1 && !self.non_zero_reminder {
157 last_bit = frac & 1;
158 }
159
160 if last_bit == 1 {
161 frac += 1;
162 }
163
164 frac
165 }
166
167 pub fn to_f64(self) -> f64 {
168 f64::from_bits(self.get_f64_bits())
169 }
170
171 fn get_f64_bits(self) -> u64 {
172 const PRECISION: u64 = 52;
173 const MAX_FRAC: u64 = 1 << (PRECISION + 1);
174 const FRAC_MASK: u64 = (1 << PRECISION) - 1;
175 const INF_BITS: u64 = 2047 << 52;
176
177 let mut bits: u64 = 0;
178 if self.sign == Sign::Negative {
179 bits |= 1 << 63;
180 }
181
182 if is_zero(self.significand.deref()) {
183 return bits;
184 }
185
186 let mut value = BigFloat {
187 manager: self.manager,
188 significand: self.significand,
189 sign: self.sign,
190 exp: self.exp,
191 non_zero_reminder: self.non_zero_reminder,
192 };
193 value.increase_significand(PRECISION + 1);
194 value.decrease_significand(PRECISION + 2);
195
196 let mut f64_exp = value.exp + PRECISION as i64 + 1;
197 match f64_exp {
198 -1022..=1023 => {
199 let mut frac = value.get_frac_round();
200 if frac == MAX_FRAC {
201 frac >>= 1;
202 f64_exp += 1;
203 }
206
207 let exp_bits = (f64_exp + 1023) as u64;
208 bits |= exp_bits << 52;
209 let frac_bits = frac & FRAC_MASK;
210 bits |= frac_bits;
211 bits
212 }
213 -1074..=-1023 => {
214 let subnormal_precision = (f64_exp + 1076) as u64;
215 value.decrease_significand(subnormal_precision);
216 let frac = value.get_frac_round();
217 bits |= frac;
220 bits
221 }
222 exp if exp > 1023 => {
223 bits |= INF_BITS;
224 bits
225 }
226 _ => bits,
227 }
228 }
229}
230
231#[cfg(test)]
232mod test {
233 use wasm_bindgen_test::wasm_bindgen_test;
234
235 use crate::{
236 big_numbers::big_float::float_zero,
237 js::{
238 any::Any,
239 js_bigint::{from_u64, new_bigint, zero, JsBigintRef, Sign},
240 type_::Type,
241 },
242 mem::global::{Global, GLOBAL},
243 };
244
245 use super::BigFloat;
246
247 #[test]
248 #[wasm_bindgen_test]
249 fn test_zero() {
250 type A = Any<Global>;
251 type BigintRef = JsBigintRef<Global>;
252
253 let res = float_zero(GLOBAL).to_bin(64);
254 let any = A::move_from(res.significand.to_ref());
255 assert_eq!(any.get_type(), Type::Bigint);
256 {
257 let o = any.try_move::<BigintRef>().unwrap();
258 assert_eq!(o.sign(), Sign::Positive);
259 assert!(o.items().is_empty());
260 }
261 assert_eq!(res.exp, 0);
262 assert!(!res.non_zero_reminder);
263
264 let res = BigFloat {
265 manager: GLOBAL,
266 significand: zero(GLOBAL),
267 sign: Sign::Positive,
268 exp: 10,
269 non_zero_reminder: false,
270 }
271 .to_bin(64);
272 let any = A::move_from(res.significand.to_ref());
273 assert_eq!(any.get_type(), Type::Bigint);
274 {
275 let o = any.try_move::<BigintRef>().unwrap();
276 assert_eq!(o.sign(), Sign::Positive);
277 assert!(o.items().is_empty());
278 }
279 assert_eq!(res.exp, 0);
280 assert!(!res.non_zero_reminder);
281
282 let res = BigFloat {
283 manager: GLOBAL,
284 significand: zero(GLOBAL),
285 sign: Sign::Positive,
286 exp: -10,
287 non_zero_reminder: false,
288 }
289 .to_bin(64);
290 let any = A::move_from(res.significand.to_ref());
291 assert_eq!(any.get_type(), Type::Bigint);
292 {
293 let o = any.try_move::<BigintRef>().unwrap();
294 assert_eq!(o.sign(), Sign::Positive);
295 assert!(o.items().is_empty());
296 }
297 assert_eq!(res.exp, 0);
298 assert!(!res.non_zero_reminder);
299 }
300
301 #[test]
302 #[wasm_bindgen_test]
303 fn test_integer() {
304 type A = Any<Global>;
305 type BigintRef = JsBigintRef<Global>;
306
307 let res = BigFloat {
308 manager: GLOBAL,
309 significand: from_u64(GLOBAL, Sign::Positive, 100),
310 sign: Sign::Positive,
311 exp: 0,
312 non_zero_reminder: false,
313 }
314 .to_bin(7);
315 let any = A::move_from(res.significand.to_ref());
316 assert_eq!(any.get_type(), Type::Bigint);
317 {
318 let o = any.try_move::<BigintRef>().unwrap();
319 assert_eq!(o.sign(), Sign::Positive);
320 assert_eq!(o.items(), &[100]);
321 }
322 assert_eq!(res.exp, 0);
323 assert!(!res.non_zero_reminder);
324
325 let res = BigFloat {
326 manager: GLOBAL,
327 significand: from_u64(GLOBAL, Sign::Positive, 1),
328 sign: Sign::Positive,
329 exp: 1,
330 non_zero_reminder: false,
331 }
332 .to_bin(64);
333 let any = A::move_from(res.significand.to_ref());
334 assert_eq!(any.get_type(), Type::Bigint);
335 {
336 let o = any.try_move::<BigintRef>().unwrap();
337 assert_eq!(o.sign(), Sign::Positive);
338 assert_eq!(o.items(), &[10 << 60]);
339 }
340 assert_eq!(res.exp, -60);
341 assert!(!res.non_zero_reminder);
342
343 let res = BigFloat {
344 manager: GLOBAL,
345 significand: from_u64(GLOBAL, Sign::Positive, 100),
346 sign: Sign::Positive,
347 exp: 2,
348 non_zero_reminder: false,
349 }
350 .to_bin(64);
351 let any = A::move_from(res.significand.to_ref());
352 assert_eq!(any.get_type(), Type::Bigint);
353 {
354 let o = any.try_move::<BigintRef>().unwrap();
355 assert_eq!(o.sign(), Sign::Positive);
356 assert_eq!(o.items(), &[10000 << 50]);
357 }
358 assert_eq!(res.exp, -50);
359 assert!(!res.non_zero_reminder);
360
361 let res = BigFloat {
362 manager: GLOBAL,
363 significand: from_u64(GLOBAL, Sign::Positive, 128),
364 sign: Sign::Positive,
365 exp: 0,
366 non_zero_reminder: false,
367 }
368 .to_bin(9);
369 let any = A::move_from(res.significand.to_ref());
370 assert_eq!(any.get_type(), Type::Bigint);
371 {
372 let o = any.try_move::<BigintRef>().unwrap();
373 assert_eq!(o.sign(), Sign::Positive);
374 assert_eq!(o.items(), &[256]);
375 }
376 assert_eq!(res.exp, -1);
377 assert!(!res.non_zero_reminder);
378 }
379
380 #[test]
381 #[wasm_bindgen_test]
382 fn test_integer_rounding() {
383 type A = Any<Global>;
384 type BigintRef = JsBigintRef<Global>;
385
386 let res = BigFloat {
387 manager: GLOBAL,
388 significand: from_u64(GLOBAL, Sign::Positive, 128),
389 sign: Sign::Positive,
390 exp: 0,
391 non_zero_reminder: false,
392 }
393 .to_bin(4);
394 let any = A::move_from(res.significand.to_ref());
395 assert_eq!(any.get_type(), Type::Bigint);
396 {
397 let o = any.try_move::<BigintRef>().unwrap();
398 assert_eq!(o.sign(), Sign::Positive);
399 assert_eq!(o.items(), &[8]);
400 }
401 assert_eq!(res.exp, 4);
402 assert!(!res.non_zero_reminder);
403
404 let res = BigFloat {
405 manager: GLOBAL,
406 significand: from_u64(GLOBAL, Sign::Positive, 129),
407 sign: Sign::Positive,
408 exp: 0,
409 non_zero_reminder: false,
410 }
411 .to_bin(4);
412 let any = A::move_from(res.significand.to_ref());
413 assert_eq!(any.get_type(), Type::Bigint);
414 {
415 let o = any.try_move::<BigintRef>().unwrap();
416 assert_eq!(o.sign(), Sign::Positive);
417 assert_eq!(o.items(), &[8]);
418 }
419 assert_eq!(res.exp, 4);
420 assert!(res.non_zero_reminder);
421 }
422
423 #[test]
424 #[wasm_bindgen_test]
425 fn test_float() {
426 type A = Any<Global>;
427 type BigintRef = JsBigintRef<Global>;
428
429 let res = BigFloat {
430 manager: GLOBAL,
431 significand: from_u64(GLOBAL, Sign::Positive, 100),
432 sign: Sign::Positive,
433 exp: -1,
434 non_zero_reminder: false,
435 }
436 .to_bin(5);
437 let any = A::move_from(res.significand.to_ref());
438 assert_eq!(any.get_type(), Type::Bigint);
439 {
440 let o = any.try_move::<BigintRef>().unwrap();
441 assert_eq!(o.sign(), Sign::Positive);
442 assert_eq!(o.items(), &[20]);
443 }
444 assert_eq!(res.exp, -1);
445 assert!(!res.non_zero_reminder);
446
447 let res = BigFloat {
448 manager: GLOBAL,
449 significand: from_u64(GLOBAL, Sign::Positive, 100),
450 sign: Sign::Positive,
451 exp: -1,
452 non_zero_reminder: false,
453 }
454 .to_bin(64);
455 let any = A::move_from(res.significand.to_ref());
456 assert_eq!(any.get_type(), Type::Bigint);
457 {
458 let o = any.try_move::<BigintRef>().unwrap();
459 assert_eq!(o.sign(), Sign::Positive);
460 assert_eq!(o.items(), &[(1 << 63) + (1 << 61)]);
461 }
462 assert_eq!(res.exp, -60);
463 assert!(!res.non_zero_reminder);
464
465 let res = BigFloat {
466 manager: GLOBAL,
467 significand: new_bigint(GLOBAL, Sign::Positive, [0, 1]),
468 sign: Sign::Positive,
469 exp: 0,
470 non_zero_reminder: false,
471 }
472 .to_bin(53);
473 let any = A::move_from(res.significand.to_ref());
474 assert_eq!(any.get_type(), Type::Bigint);
475 {
476 let o = any.try_move::<BigintRef>().unwrap();
477 assert_eq!(o.sign(), Sign::Positive);
478 assert_eq!(o.items(), &[1 << 52]);
479 }
480 assert_eq!(res.exp, 12);
481 assert!(!res.non_zero_reminder);
482 }
483
484 #[test]
485 #[wasm_bindgen_test]
486 fn test_rounding() {
487 type A = Any<Global>;
488 type BigintRef = JsBigintRef<Global>;
489
490 let res = BigFloat {
491 manager: GLOBAL,
492 significand: from_u64(GLOBAL, Sign::Positive, 0b1000_0001),
493 sign: Sign::Positive,
494 exp: -1,
495 non_zero_reminder: false,
496 }
497 .to_bin(5);
498 let any = A::move_from(res.significand.to_ref());
499 assert_eq!(any.get_type(), Type::Bigint);
500 {
501 let o = any.try_move::<BigintRef>().unwrap();
502 assert_eq!(o.sign(), Sign::Positive);
503 assert_eq!(o.items(), &[0b11001]);
504 }
505 assert_eq!(res.exp, -1);
506 assert!(res.non_zero_reminder);
507
508 let res = BigFloat {
509 manager: GLOBAL,
510 significand: from_u64(GLOBAL, Sign::Positive, 0b1000_0001),
511 sign: Sign::Positive,
512 exp: -1,
513 non_zero_reminder: false,
514 }
515 .to_bin(4);
516 let any = A::move_from(res.significand.to_ref());
517 assert_eq!(any.get_type(), Type::Bigint);
518 {
519 let o = any.try_move::<BigintRef>().unwrap();
520 assert_eq!(o.sign(), Sign::Positive);
521 assert_eq!(o.items(), &[0b1100]);
522 }
523 assert_eq!(res.exp, 0);
524 assert!(res.non_zero_reminder);
525
526 let res = BigFloat {
527 manager: GLOBAL,
528 significand: from_u64(GLOBAL, Sign::Positive, 0b1000_0001),
529 sign: Sign::Positive,
530 exp: -1,
531 non_zero_reminder: false,
532 }
533 .to_bin(3);
534 let any = A::move_from(res.significand.to_ref());
535 assert_eq!(any.get_type(), Type::Bigint);
536 {
537 let o = any.try_move::<BigintRef>().unwrap();
538 assert_eq!(o.sign(), Sign::Positive);
539 assert_eq!(o.items(), &[0b110]);
540 }
541 assert_eq!(res.exp, 1);
542 assert!(res.non_zero_reminder);
543 }
544
545 #[test]
546 #[wasm_bindgen_test]
547 fn test_rounding_half() {
548 type A = Any<Global>;
549 type BigintRef = JsBigintRef<Global>;
550
551 let res = BigFloat {
552 manager: GLOBAL,
553 significand: from_u64(GLOBAL, Sign::Positive, 0b101_1010),
554 sign: Sign::Positive,
555 exp: -1,
556 non_zero_reminder: false,
557 }
558 .to_bin(3);
559 let any = A::move_from(res.significand.to_ref());
560 assert_eq!(any.get_type(), Type::Bigint);
561 {
562 let o = any.try_move::<BigintRef>().unwrap();
563 assert_eq!(o.sign(), Sign::Positive);
564 assert_eq!(o.items(), &[0b100]);
565 }
566 assert_eq!(res.exp, 1);
567 assert!(res.non_zero_reminder);
568
569 let res = BigFloat {
570 manager: GLOBAL,
571 significand: from_u64(GLOBAL, Sign::Positive, 0b101_1011),
572 sign: Sign::Positive,
573 exp: -1,
574 non_zero_reminder: false,
575 }
576 .to_bin(3);
577 let any = A::move_from(res.significand.to_ref());
578 assert_eq!(any.get_type(), Type::Bigint);
579 {
580 let o = any.try_move::<BigintRef>().unwrap();
581 assert_eq!(o.sign(), Sign::Positive);
582 assert_eq!(o.items(), &[0b100]);
583 }
584 assert_eq!(res.exp, 1);
585 assert!(res.non_zero_reminder);
586
587 let res = BigFloat {
588 manager: GLOBAL,
589 significand: from_u64(GLOBAL, Sign::Positive, 0b110_1101),
590 sign: Sign::Positive,
591 exp: -1,
592 non_zero_reminder: false,
593 }
594 .to_bin(3);
595 let any = A::move_from(res.significand.to_ref());
596 assert_eq!(any.get_type(), Type::Bigint);
597 {
598 let o = any.try_move::<BigintRef>().unwrap();
599 assert_eq!(o.sign(), Sign::Positive);
600 assert_eq!(o.items(), &[0b101]);
601 }
602 assert_eq!(res.exp, 1);
603 assert!(res.non_zero_reminder);
604
605 let res = BigFloat {
606 manager: GLOBAL,
607 significand: from_u64(GLOBAL, Sign::Positive, 0b110_1110),
608 sign: Sign::Positive,
609 exp: -1,
610 non_zero_reminder: false,
611 }
612 .to_bin(3);
613 let any = A::move_from(res.significand.to_ref());
614 assert_eq!(any.get_type(), Type::Bigint);
615 {
616 let o = any.try_move::<BigintRef>().unwrap();
617 assert_eq!(o.sign(), Sign::Positive);
618 assert_eq!(o.items(), &[0b101]);
619 }
620 assert_eq!(res.exp, 1);
621 assert!(res.non_zero_reminder);
622
623 let res = BigFloat {
624 manager: GLOBAL,
625 significand: from_u64(GLOBAL, Sign::Positive, 0b1001_0110),
626 sign: Sign::Positive,
627 exp: -1,
628 non_zero_reminder: false,
629 }
630 .to_bin(3);
631 let any = A::move_from(res.significand.to_ref());
632 assert_eq!(any.get_type(), Type::Bigint);
633 {
634 let o = any.try_move::<BigintRef>().unwrap();
635 assert_eq!(o.sign(), Sign::Positive);
636 assert_eq!(o.items(), &[0b111]);
637 }
638 assert_eq!(res.exp, 1);
639 assert!(res.non_zero_reminder);
640 }
641
642 #[test]
643 #[wasm_bindgen_test]
644 fn test_zero_to_f64() {
645 type A = Any<Global>;
646 type BigintRef = JsBigintRef<Global>;
647
648 let res = BigFloat {
649 manager: GLOBAL,
650 significand: zero(GLOBAL),
651 sign: Sign::Positive,
652 exp: 100,
653 non_zero_reminder: false,
654 }
655 .to_f64();
656 assert_eq!(res, 0.0);
657 assert!(res.is_sign_positive());
658
659 let res = BigFloat {
660 manager: GLOBAL,
661 significand: zero(GLOBAL),
662 sign: Sign::Negative,
663 exp: 100,
664 non_zero_reminder: false,
665 }
666 .to_f64();
667 assert_eq!(res, 0.0);
668 assert!(res.is_sign_negative());
669 }
670
671 #[test]
672 #[wasm_bindgen_test]
673 fn test_normal_to_f64() {
674 type A = Any<Global>;
675 type BigintRef = JsBigintRef<Global>;
676
677 let res = BigFloat {
678 manager: GLOBAL,
679 significand: from_u64(GLOBAL, Sign::Positive, 1),
680 sign: Sign::Positive,
681 exp: 0,
682 non_zero_reminder: false,
683 }
684 .to_f64();
685 assert_eq!(res, 1.0);
686
687 let res = BigFloat {
688 manager: GLOBAL,
689 significand: from_u64(GLOBAL, Sign::Positive, 3),
690 sign: Sign::Negative,
691 exp: -1,
692 non_zero_reminder: false,
693 }
694 .to_f64();
695 assert_eq!(res, -1.5);
696
697 let res = BigFloat {
698 manager: GLOBAL,
699 significand: from_u64(GLOBAL, Sign::Positive, 1),
700 sign: Sign::Positive,
701 exp: -1022,
702 non_zero_reminder: false,
703 }
704 .to_f64();
705 assert_eq!(res, 2.0f64.powf(-1022.0));
706 assert!(res.is_normal());
707
708 let res = BigFloat {
709 manager: GLOBAL,
710 significand: from_u64(GLOBAL, Sign::Positive, 1 << 59),
711 sign: Sign::Positive,
712 exp: -1022 - 59,
713 non_zero_reminder: false,
714 }
715 .to_f64();
716 assert_eq!(res, 2.0f64.powf(-1022.0));
717 assert!(res.is_normal());
718
719 let res = BigFloat {
720 manager: GLOBAL,
721 significand: from_u64(GLOBAL, Sign::Positive, (1 << 60) - 1),
722 sign: Sign::Positive,
723 exp: -1022 - 60,
724 non_zero_reminder: false,
725 }
726 .to_f64();
727 assert_eq!(res, 2.0f64.powf(-1022.0));
728 assert!(res.is_normal());
729
730 let res = BigFloat {
731 manager: GLOBAL,
732 significand: from_u64(GLOBAL, Sign::Positive, 1),
733 sign: Sign::Positive,
734 exp: 1023,
735 non_zero_reminder: false,
736 }
737 .to_f64();
738 assert_eq!(res, 2.0f64.powf(1023.0));
739
740 let res = BigFloat {
741 manager: GLOBAL,
742 significand: from_u64(GLOBAL, Sign::Positive, (1 << 52) - 1),
743 sign: Sign::Positive,
744 exp: 0,
745 non_zero_reminder: false,
746 }
747 .to_f64();
748 assert_eq!(res, 4503599627370495f64);
749
750 let res = BigFloat {
751 manager: GLOBAL,
752 significand: from_u64(GLOBAL, Sign::Positive, (1 << 53) - 1),
753 sign: Sign::Positive,
754 exp: 0,
755 non_zero_reminder: false,
756 }
757 .to_f64();
758 assert_eq!(res, 9007199254740991f64);
759 }
760
761 #[test]
762 #[wasm_bindgen_test]
763 fn test_normal_to_f64_rounding() {
764 type A = Any<Global>;
765 type BigintRef = JsBigintRef<Global>;
766
767 let res = BigFloat {
768 manager: GLOBAL,
769 significand: from_u64(GLOBAL, Sign::Positive, (1 << 54) - 1), sign: Sign::Positive,
771 exp: 0,
772 non_zero_reminder: false,
773 }
774 .to_f64();
775 assert_eq!(res, 18014398509481984f64);
776
777 let res = BigFloat {
778 manager: GLOBAL,
779 significand: from_u64(GLOBAL, Sign::Positive, (1 << 54) - 2), sign: Sign::Positive,
781 exp: 0,
782 non_zero_reminder: false,
783 }
784 .to_f64();
785 assert_eq!(res, 18014398509481982f64);
786
787 let res = BigFloat {
788 manager: GLOBAL,
789 significand: from_u64(GLOBAL, Sign::Positive, (1 << 54) - 3), sign: Sign::Positive,
791 exp: 0,
792 non_zero_reminder: true,
793 }
794 .to_f64();
795 assert_eq!(res, 18014398509481982f64);
796
797 let res = BigFloat {
798 manager: GLOBAL,
799 significand: from_u64(GLOBAL, Sign::Positive, (1 << 54) - 3), sign: Sign::Positive,
801 exp: 0,
802 non_zero_reminder: false,
803 }
804 .to_f64();
805 assert_eq!(res, 18014398509481980f64);
806
807 let res = BigFloat {
808 manager: GLOBAL,
809 significand: from_u64(GLOBAL, Sign::Positive, (1 << 54) - 1),
810 sign: Sign::Positive,
811 exp: 969,
812 non_zero_reminder: false,
813 }
814 .to_f64();
815 assert!(res.is_normal());
816
817 let res = BigFloat {
818 manager: GLOBAL,
819 significand: from_u64(GLOBAL, Sign::Positive, (1 << 54) - 1),
820 sign: Sign::Positive,
821 exp: 970,
822 non_zero_reminder: false,
823 }
824 .to_f64();
825 assert!(res.is_infinite());
826 }
827
828 #[test]
829 #[wasm_bindgen_test]
830 fn test_infinity_to_f64() {
831 type A = Any<Global>;
832 type BigintRef = JsBigintRef<Global>;
833
834 let res = BigFloat {
835 manager: GLOBAL,
836 significand: from_u64(GLOBAL, Sign::Positive, 1),
837 sign: Sign::Positive,
838 exp: 1024,
839 non_zero_reminder: false,
840 }
841 .to_f64();
842 assert!(res.is_infinite());
843 assert!(res.is_sign_positive());
844
845 let res = BigFloat {
846 manager: GLOBAL,
847 significand: from_u64(GLOBAL, Sign::Positive, 1),
848 sign: Sign::Negative,
849 exp: 1024,
850 non_zero_reminder: false,
851 }
852 .to_f64();
853 assert!(res.is_infinite());
854 assert!(res.is_sign_negative());
855 }
856
857 #[test]
858 #[wasm_bindgen_test]
859 fn test_subnormal_to_f64() {
860 type A = Any<Global>;
861 type BigintRef = JsBigintRef<Global>;
862
863 let res = BigFloat {
864 manager: GLOBAL,
865 significand: from_u64(GLOBAL, Sign::Positive, 1),
866 sign: Sign::Positive,
867 exp: -1023,
868 non_zero_reminder: false,
869 }
870 .to_f64();
871 assert_eq!(res, 2.0f64.powf(-1023.0));
872 assert!(res.is_subnormal());
873
874 let res = BigFloat {
875 manager: GLOBAL,
876 significand: from_u64(GLOBAL, Sign::Positive, 1),
877 sign: Sign::Negative,
878 exp: -1023,
879 non_zero_reminder: false,
880 }
881 .to_f64();
882 assert_eq!(res, -(2.0f64.powf(-1023.0)));
883 assert!(res.is_subnormal());
884
885 let res = BigFloat {
886 manager: GLOBAL,
887 significand: from_u64(GLOBAL, Sign::Positive, 1),
888 sign: Sign::Positive,
889 exp: -1074,
890 non_zero_reminder: false,
891 }
892 .to_f64();
893 assert_eq!(res.to_bits(), 1);
894 assert_eq!(res, 2.0f64.powf(-1074.0));
895 assert!(res.is_subnormal());
896
897 let res = BigFloat {
898 manager: GLOBAL,
899 significand: from_u64(GLOBAL, Sign::Positive, 1),
900 sign: Sign::Positive,
901 exp: -1075,
902 non_zero_reminder: false,
903 }
904 .to_f64();
905 assert_eq!(res, 0.0);
906 }
907
908 #[test]
909 #[wasm_bindgen_test]
910 fn test_subnormal_to_f64_rounding() {
911 type A = Any<Global>;
912 type BigintRef = JsBigintRef<Global>;
913
914 let res = BigFloat {
916 manager: GLOBAL,
917 significand: from_u64(GLOBAL, Sign::Positive, 0b100),
918 sign: Sign::Positive,
919 exp: -1075,
920 non_zero_reminder: false,
921 }
922 .to_f64();
923 assert_eq!(res.to_bits(), 0b10);
924 assert_eq!(res, 2.0f64.powf(-1073.0));
925 assert!(res.is_subnormal());
926
927 let res = BigFloat {
929 manager: GLOBAL,
930 significand: from_u64(GLOBAL, Sign::Positive, 0b100),
931 sign: Sign::Positive,
932 exp: -1075,
933 non_zero_reminder: true,
934 }
935 .to_f64();
936 assert_eq!(res.to_bits(), 0b10);
937 assert_eq!(res, 2.0f64.powf(-1073.0));
938 assert!(res.is_subnormal());
939
940 let res = BigFloat {
942 manager: GLOBAL,
943 significand: from_u64(GLOBAL, Sign::Positive, 0b101),
944 sign: Sign::Positive,
945 exp: -1075,
946 non_zero_reminder: false,
947 }
948 .to_f64();
949 assert_eq!(res.to_bits(), 0b10);
950 assert_eq!(res, 2.0f64.powf(-1073.0));
951 assert!(res.is_subnormal());
952
953 let res = BigFloat {
955 manager: GLOBAL,
956 significand: from_u64(GLOBAL, Sign::Positive, 0b101),
957 sign: Sign::Positive,
958 exp: -1075,
959 non_zero_reminder: true,
960 }
961 .to_f64();
962 assert_eq!(res.to_bits(), 0b11);
963 assert_eq!(res, 1.5f64 * 2.0f64.powf(-1073.0));
964 assert!(res.is_subnormal());
965
966 let res = BigFloat {
968 manager: GLOBAL,
969 significand: from_u64(GLOBAL, Sign::Positive, 0b110),
970 sign: Sign::Positive,
971 exp: -1075,
972 non_zero_reminder: false,
973 }
974 .to_f64();
975 assert_eq!(res.to_bits(), 0b11);
976 assert_eq!(res, 1.5f64 * 2.0f64.powf(-1073.0));
977 assert!(res.is_subnormal());
978
979 let res = BigFloat {
981 manager: GLOBAL,
982 significand: from_u64(GLOBAL, Sign::Positive, 0b110),
983 sign: Sign::Positive,
984 exp: -1075,
985 non_zero_reminder: true,
986 }
987 .to_f64();
988 assert_eq!(res.to_bits(), 0b11);
989 assert_eq!(res, 1.5f64 * 2.0f64.powf(-1073.0));
990 assert!(res.is_subnormal());
991
992 let res = BigFloat {
994 manager: GLOBAL,
995 significand: from_u64(GLOBAL, Sign::Positive, 0b111),
996 sign: Sign::Positive,
997 exp: -1075,
998 non_zero_reminder: false,
999 }
1000 .to_f64();
1001 assert_eq!(res.to_bits(), 0b100);
1002 assert_eq!(res, 2.0f64.powf(-1072.0));
1003 assert!(res.is_subnormal());
1004
1005 let res = BigFloat {
1007 manager: GLOBAL,
1008 significand: from_u64(GLOBAL, Sign::Positive, 0b111),
1009 sign: Sign::Positive,
1010 exp: -1075,
1011 non_zero_reminder: true,
1012 }
1013 .to_f64();
1014 assert_eq!(res.to_bits(), 0b100);
1015 assert_eq!(res, 2.0f64.powf(-1072.0));
1016 assert!(res.is_subnormal());
1017 }
1018
1019 #[test]
1020 #[wasm_bindgen_test]
1021 fn test_rust_cast() {
1022 test(18014398509481981);
1023 test(18014398509481982);
1024 test(18014398509481983);
1025 test(18014398509481984);
1026 test(18014398509481985);
1027
1028 fn test(n: u64) {
1029 type A = Any<Global>;
1030 type BigintRef = JsBigintRef<Global>;
1031
1032 let res = BigFloat {
1033 manager: GLOBAL,
1034 significand: from_u64(GLOBAL, Sign::Positive, n),
1035 sign: Sign::Positive,
1036 exp: 0,
1037 non_zero_reminder: false,
1038 }
1039 .to_f64();
1040 assert_eq!(res, n as f64);
1041 }
1042 }
1043}