1const EXP_MASK: u64 = 0x7FF0_0000_0000_0000;
9
10const FIRST_ONE: u64 = 0x8000_0000_0000_0000;
12
13const NEG_ONE: u64 = 0xFFFF_FFFF_FFFF_FFFF;
15
16#[derive(Debug, Clone)]
23pub struct PrecisionBound {
24 position: u64,
26 precision: f64,
28 precision_exp: i32,
30 int_length: u64,
32 decimal_length: u64,
34}
35
36impl PrecisionBound {
37 pub fn new(precision: f64) -> Self {
49 let xu = precision.to_bits();
50 let precision_exp = ((xu & EXP_MASK) >> 52) as i32 - 1023;
51
52 PrecisionBound {
53 position: 0,
54 precision,
55 precision_exp,
56 int_length: 0,
57 decimal_length: 0,
58 }
59 }
60
61 pub fn precision_bound(&mut self, orig: f64) -> f64 {
66 let mask = !0u64;
67 let origu = orig.to_bits();
68
69 let mut curu = origu & (mask << self.position) | (1u64 << self.position);
70 let mut cur = f64::from_bits(curu);
71 let mut pre = cur;
72 let bounded = self.is_bounded(orig, cur);
73
74 if bounded {
75 loop {
77 if self.position == 52 {
78 return pre;
79 }
80 self.position += 1;
81 curu = origu & (mask << self.position) | (1u64 << self.position);
82 cur = f64::from_bits(curu);
83 if !self.is_bounded(orig, cur) {
84 break;
85 }
86 pre = cur;
87 }
88 } else {
89 loop {
91 if self.position == 0 {
92 break;
93 }
94 self.position -= 1;
95 curu = origu & (mask << self.position) | (1u64 << self.position);
96 cur = f64::from_bits(curu);
97 if self.is_bounded(orig, cur) {
98 pre = cur;
99 break;
100 }
101 }
102 }
103 pre
104 }
105
106 pub fn cal_length(&mut self, x: f64) {
108 let xu = x.to_bits();
109 let trailing_zeros = xu.trailing_zeros();
110 let exp = ((xu & EXP_MASK) >> 52) as i32 - 1023;
111
112 let mut dec_length = 0u64;
113 if trailing_zeros >= 52 {
114 if exp < 0 {
115 dec_length = (-exp) as u64;
116 if exp < self.precision_exp {
117 dec_length = 0;
118 }
119 }
120 } else if (52 - trailing_zeros as i32) > exp {
121 dec_length = ((52 - trailing_zeros as i32) - exp) as u64;
122 }
123
124 if exp >= 0 && (exp + 1) as u64 > self.int_length {
125 self.int_length = (exp + 1) as u64;
126 }
127 if dec_length > self.decimal_length {
128 self.decimal_length = dec_length;
129 }
130 }
131
132 pub fn get_length(&self) -> (u64, u64) {
134 (self.int_length, self.decimal_length)
135 }
136
137 #[inline]
139 pub fn set_length(&mut self, ilen: u64, dlen: u64) {
140 self.int_length = ilen;
141 self.decimal_length = dlen;
142 }
143
144 #[inline]
146 pub fn fetch_components(&self, bd: f64) -> (i64, u64) {
147 let bdu = bd.to_bits();
148 let exp = ((bdu & EXP_MASK) >> 52) as i32 - 1023;
149 let sign = bdu & FIRST_ONE;
150 let mut int_part = 0u64;
151 let mut dec_part: u64;
152
153 if exp >= 0 {
154 dec_part = bdu << (12 + exp) as u64;
155 int_part = ((bdu << 11) | FIRST_ONE) >> (63 - exp) as u64;
156 if sign != 0 {
157 int_part = !int_part;
158 dec_part = (!dec_part).wrapping_add(1);
159 }
160 } else if exp < self.precision_exp {
161 dec_part = 0u64;
162 if sign != 0 {
163 int_part = NEG_ONE;
164 dec_part = !dec_part;
165 }
166 } else {
167 dec_part = ((bdu << 11) | FIRST_ONE) >> ((-exp - 1) as u64);
168 if sign != 0 {
169 int_part = NEG_ONE;
170 dec_part = !dec_part;
171 }
172 }
173
174 let signed_int = int_part as i64;
175 (signed_int, dec_part >> (64u64 - self.decimal_length))
176 }
177
178 #[inline]
183 pub fn fetch_fixed_aligned(&self, bd: f64) -> i64 {
184 let bdu = bd.to_bits();
185 let exp = ((bdu & EXP_MASK) >> 52) as i32 - 1023;
186 let sign = bdu & FIRST_ONE;
187 let mut fixed: u64;
188
189 if exp < self.precision_exp {
190 fixed = 0u64;
191 } else {
192 fixed = ((bdu << 11) | FIRST_ONE) >> (63 - exp - self.decimal_length as i32) as u64;
193 if sign != 0 {
194 fixed = !(fixed.wrapping_sub(1));
195 }
196 }
197
198 fixed as i64
199 }
200
201 #[inline]
203 pub fn is_bounded(&self, a: f64, b: f64) -> bool {
204 (a - b).abs() < self.precision
205 }
206}
207
208pub fn get_precision_bound(precision: i32) -> f64 {
216 if precision <= 0 {
217 return 0.49;
218 }
219
220 let mut s = String::from("0.");
221 for _ in 0..precision {
222 s.push('0');
223 }
224 s.push_str("49");
225 s.parse().unwrap_or(0.49)
226}
227
228pub const PRECISION_MAP: [(i32, u64); 16] = [
232 (0, 0),
233 (1, 4),
234 (2, 7),
235 (3, 10),
236 (4, 14),
237 (5, 17),
238 (6, 20),
239 (7, 24),
240 (8, 27),
241 (9, 30),
242 (10, 34),
243 (11, 37),
244 (12, 40),
245 (13, 44),
246 (14, 47),
247 (15, 50),
248];
249
250pub fn get_decimal_length(precision: i32) -> u64 {
252 PRECISION_MAP
253 .iter()
254 .find(|(p, _)| *p == precision)
255 .map(|(_, len)| *len)
256 .unwrap_or(0)
257}
258
259#[cfg(test)]
260mod tests {
261 use super::*;
262
263 #[test]
264 fn test_precision_bound_creation() {
265 let bound = PrecisionBound::new(0.00005);
266 assert!(bound.precision > 0.0);
267 }
268
269 #[test]
270 fn test_get_precision_bound() {
271 let pb = get_precision_bound(4);
272 assert!(pb > 0.0 && pb < 0.001);
273 }
274
275 #[test]
276 fn test_is_bounded() {
277 let bound = PrecisionBound::new(0.05);
278 assert!(bound.is_bounded(1.0, 1.01));
279 assert!(!bound.is_bounded(1.0, 1.1));
280 }
281
282 #[test]
283 fn test_precision_map() {
284 assert_eq!(get_decimal_length(0), 0);
285 assert_eq!(get_decimal_length(4), 14);
286 assert_eq!(get_decimal_length(10), 34);
287 }
288
289 #[test]
290 fn test_fetch_fixed_aligned() {
291 let mut bound = PrecisionBound::new(0.00005);
292 bound.set_length(4, 14);
293
294 let fixed = bound.fetch_fixed_aligned(3.14159);
295 assert!(fixed > 0);
296 }
297
298 #[test]
299 fn test_fetch_fixed_aligned_negative() {
300 let mut bound = PrecisionBound::new(0.00005);
301 bound.set_length(4, 14);
302
303 let fixed = bound.fetch_fixed_aligned(-3.14159);
304 assert!(fixed < 0);
305 }
306
307 #[test]
308 fn test_fetch_fixed_aligned_zero() {
309 let mut bound = PrecisionBound::new(0.00005);
310 bound.set_length(4, 14);
311
312 let fixed = bound.fetch_fixed_aligned(0.0);
313 assert_eq!(fixed, 0);
314 }
315
316 #[test]
317 fn test_fetch_fixed_aligned_small() {
318 let mut bound = PrecisionBound::new(0.00005);
319 bound.set_length(4, 14);
320
321 let fixed = bound.fetch_fixed_aligned(0.00001);
323 assert!(fixed.abs() <= 1);
325 }
326
327 #[test]
328 fn test_get_length() {
329 let mut bound = PrecisionBound::new(0.00005);
330 bound.set_length(8, 16);
331
332 let (ilen, dlen) = bound.get_length();
333 assert_eq!(ilen, 8);
334 assert_eq!(dlen, 16);
335 }
336
337 #[test]
338 fn test_cal_length() {
339 let mut bound = PrecisionBound::new(0.00005);
340
341 bound.cal_length(1000.0);
343 let (ilen, _dlen) = bound.get_length();
344 assert!(ilen > 0);
345
346 let mut bound2 = PrecisionBound::new(0.00005);
348 bound2.cal_length(0.123456);
349 let (_, dlen) = bound2.get_length();
350 assert!(dlen > 0);
351 }
352
353 #[test]
354 fn test_fetch_components() {
355 let mut bound = PrecisionBound::new(0.00005);
356 bound.set_length(4, 14);
357
358 let (int_part, dec_part) = bound.fetch_components(3.5);
359 assert_eq!(int_part, 3);
360 assert!(dec_part > 0);
361 }
362
363 #[test]
364 fn test_fetch_components_negative() {
365 let mut bound = PrecisionBound::new(0.00005);
366 bound.set_length(4, 14);
367
368 let (int_part, _dec_part) = bound.fetch_components(-3.5);
369 assert!(int_part < 0);
370 }
371
372 #[test]
373 fn test_fetch_components_small_value() {
374 let mut bound = PrecisionBound::new(0.00005);
375 bound.set_length(0, 14);
376
377 let (int_part, dec_part) = bound.fetch_components(0.001);
379 assert_eq!(int_part, 0);
380 assert!(dec_part >= 0);
381 }
382
383 #[test]
384 fn test_precision_bound_method() {
385 let mut bound = PrecisionBound::new(0.005);
386
387 let result = bound.precision_bound(3.14159);
389 assert!((result - 3.14159).abs() < 0.01);
390 }
391
392 #[test]
393 fn test_precision_bound_exact() {
394 let mut bound = PrecisionBound::new(0.05);
395
396 let result = bound.precision_bound(1.0);
398 assert!((result - 1.0).abs() < 0.1);
399 }
400
401 #[test]
402 fn test_get_precision_bound_zero() {
403 let pb = get_precision_bound(0);
404 assert!((pb - 0.49).abs() < 0.01);
405 }
406
407 #[test]
408 fn test_get_precision_bound_negative() {
409 let pb = get_precision_bound(-5);
410 assert!((pb - 0.49).abs() < 0.01);
411 }
412
413 #[test]
414 fn test_get_precision_bound_high() {
415 let pb = get_precision_bound(10);
416 assert!(pb < 0.0000000001);
417 assert!(pb > 0.0);
418 }
419
420 #[test]
421 fn test_get_decimal_length_unknown() {
422 let len = get_decimal_length(99);
424 assert_eq!(len, 0);
425 }
426
427 #[test]
428 fn test_get_decimal_length_all_values() {
429 for (prec, expected_len) in PRECISION_MAP {
431 assert_eq!(get_decimal_length(prec), expected_len);
432 }
433 }
434
435 #[test]
436 fn test_precision_bound_debug() {
437 let bound = PrecisionBound::new(0.00005);
438 let debug_str = format!("{:?}", bound);
439 assert!(debug_str.contains("PrecisionBound"));
440 }
441
442 #[test]
443 fn test_precision_bound_clone() {
444 let bound = PrecisionBound::new(0.00005);
445 let cloned = bound.clone();
446 assert_eq!(bound.precision, cloned.precision);
447 }
448
449 #[test]
450 fn test_cal_length_negative_exponent() {
451 let mut bound = PrecisionBound::new(0.0005);
452
453 bound.cal_length(0.00123);
455 let (_, dlen) = bound.get_length();
456 assert!(dlen > 0);
457 }
458
459 #[test]
460 fn test_cal_length_large_exponent() {
461 let mut bound = PrecisionBound::new(0.0005);
462
463 bound.cal_length(1000000.0);
465 let (ilen, _) = bound.get_length();
466 assert!(ilen > 10); }
468
469 #[test]
470 fn test_cal_length_power_of_two() {
471 let mut bound = PrecisionBound::new(0.0005);
472
473 bound.cal_length(1024.0);
475 let (ilen, _) = bound.get_length();
476 assert!(ilen > 0);
477 }
478
479 #[test]
480 fn test_fetch_components_power_of_two() {
481 let mut bound = PrecisionBound::new(0.00005);
482 bound.set_length(16, 14);
483
484 let (int_part, dec_part) = bound.fetch_components(256.0);
485 assert_eq!(int_part, 256);
486 assert_eq!(dec_part, 0);
487 }
488
489 #[test]
490 fn test_fetch_components_with_decimal() {
491 let mut bound = PrecisionBound::new(0.00005);
492 bound.set_length(4, 14);
493
494 let (int_part, dec_part) = bound.fetch_components(5.5);
495 assert_eq!(int_part, 5);
496 assert!(dec_part > 0); }
498
499 #[test]
500 fn test_precision_bound_very_tight() {
501 let mut bound = PrecisionBound::new(0.000001); let result = bound.precision_bound(1.23456789);
504 assert!((result - 1.23456789).abs() < 0.00001);
505 }
506
507 #[test]
508 fn test_precision_bound_loose() {
509 let mut bound = PrecisionBound::new(0.5); let result = bound.precision_bound(1.7);
512 assert!((result - 1.7).abs() < 1.0);
513 }
514
515 #[test]
516 fn test_fetch_fixed_aligned_large_value() {
517 let mut bound = PrecisionBound::new(0.00005);
518 bound.set_length(20, 14);
519
520 let fixed = bound.fetch_fixed_aligned(1000000.123);
521 assert!(fixed > 0);
522 }
523
524 #[test]
525 fn test_fetch_fixed_aligned_very_small() {
526 let mut bound = PrecisionBound::new(0.00005);
527 bound.set_length(0, 14);
528
529 let fixed = bound.fetch_fixed_aligned(0.0000001);
531 assert_eq!(fixed, 0);
532 }
533
534 #[test]
535 fn test_is_bounded_same_value() {
536 let bound = PrecisionBound::new(0.05);
537 assert!(bound.is_bounded(5.0, 5.0));
538 }
539
540 #[test]
541 fn test_is_bounded_at_boundary() {
542 let bound = PrecisionBound::new(0.05);
543 assert!(bound.is_bounded(1.0, 1.049));
545 assert!(!bound.is_bounded(1.0, 1.06));
546 }
547
548 #[test]
549 fn test_get_precision_bound_various() {
550 for prec in 1..=15 {
551 let pb = get_precision_bound(prec);
552 assert!(pb > 0.0);
553 assert!(pb < 1.0);
554 }
555 }
556
557 #[test]
558 fn test_precision_map_coverage() {
559 for (prec, len) in PRECISION_MAP {
561 assert!(prec >= 0);
562 assert!(len <= 64);
563 }
564 }
565
566 #[test]
567 fn test_fetch_components_negative_exponent_below_precision() {
568 let mut bound = PrecisionBound::new(0.005); bound.set_length(0, 10);
570
571 let (int_part, dec_part) = bound.fetch_components(0.0000001);
573 assert_eq!(int_part, 0);
574 assert!(dec_part == 0 || dec_part < 10);
576 }
577
578 #[test]
579 fn test_fetch_components_negative_value_small() {
580 let mut bound = PrecisionBound::new(0.005);
581 bound.set_length(0, 10);
582
583 let (int_part, dec_part) = bound.fetch_components(-0.001);
584 assert!(int_part <= 0 || dec_part > 0);
586 }
587
588 #[test]
589 fn test_cal_length_trailing_zeros() {
590 let mut bound = PrecisionBound::new(0.0005);
591
592 bound.cal_length(8.0); let (ilen, _) = bound.get_length();
595 assert!(ilen >= 4); }
597
598 #[test]
599 fn test_precision_bound_position_52() {
600 let mut bound = PrecisionBound::new(1.0); let result = bound.precision_bound(1.0);
605 assert!((result - 1.0).abs() < 2.0);
606 }
607
608 #[test]
609 fn test_precision_bound_not_bounded_initially() {
610 let mut bound = PrecisionBound::new(0.0000001); let _ = bound.precision_bound(1.5);
615 let result = bound.precision_bound(2.123456789);
617 assert!((result - 2.123456789).abs() < 0.001);
618 }
619
620 #[test]
621 fn test_precision_bound_position_zero() {
622 let mut bound = PrecisionBound::new(0.0000000001); let result = bound.precision_bound(1.123456789012345);
626 assert!((result - 1.123456789012345).abs() < 0.0001);
627 }
628
629 #[test]
630 fn test_fetch_components_negative_exp_below_precision() {
631 let mut bound = PrecisionBound::new(0.01); bound.set_length(0, 14);
634
635 let (int_part, dec_part) = bound.fetch_components(-0.0001);
637 assert!(int_part < 0 || dec_part > 0);
639 }
640
641 #[test]
642 fn test_fetch_components_negative_sign_handling() {
643 let mut bound = PrecisionBound::new(0.00005);
645 bound.set_length(4, 14);
646
647 let (int_part, dec_part) = bound.fetch_components(-0.5);
648 assert!(int_part < 0 || dec_part > 0);
650 }
651
652 #[test]
653 fn test_fetch_fixed_aligned_negative_exp_above_precision() {
654 let mut bound = PrecisionBound::new(0.01);
656 bound.set_length(0, 14);
657
658 let fixed = bound.fetch_fixed_aligned(0.25); assert!(fixed != 0);
660 }
661
662 #[test]
663 fn test_fetch_fixed_aligned_negative_sign() {
664 let mut bound = PrecisionBound::new(0.00005);
666 bound.set_length(4, 14);
667
668 let fixed = bound.fetch_fixed_aligned(-0.25);
669 assert!(fixed < 0);
670 }
671
672 #[test]
673 fn test_cal_length_exp_negative_above_precision() {
674 let mut bound = PrecisionBound::new(0.01); bound.cal_length(0.25); let (_, dlen) = bound.get_length();
679 assert!(dlen > 0);
680 }
681
682 #[test]
683 fn test_cal_length_trailing_zeros_with_decimal() {
684 let mut bound = PrecisionBound::new(0.1);
686
687 bound.cal_length(0.5);
689 let (_, dlen) = bound.get_length();
690 assert!(dlen >= 0);
691 }
692
693 #[test]
694 fn test_precision_bound_finds_bounded_then_not() {
695 let mut bound = PrecisionBound::new(0.1);
697
698 let result = bound.precision_bound(3.14159);
699 assert!((result - 3.14159).abs() < 0.2);
701 }
702
703 #[test]
704 fn test_precision_bound_finds_unbounded_then_bounded() {
705 let mut bound = PrecisionBound::new(0.001);
707 bound.position = 10; let result = bound.precision_bound(1.5);
710 assert!((result - 1.5).abs() < 0.01);
711 }
712}