use dashu_base::EstimatedLog2; mod helper_macros; #[test] fn test_log_ubig() { let test_cases = [ // trivial cases (ubig!(1), ubig!(2), 0), (ubig!(1), ubig!(10), 0), (ubig!(1), ubig!(1000), 0), (ubig!(2), ubig!(2), 1), (ubig!(3), ubig!(2), 1), (ubig!(1) << 100, ubig!(2), 100), (ubig!(1) << 1000, ubig!(2), 1000), (ubig!(123456), ubig!(123456), 1), ((ubig!(1) << 100) - 1u8, (ubig!(1) << 100) - 1u8, 1), (ubig!(1) << 1000, ubig!(1) << 1000, 1), (ubig!(123456), ubig!(123457), 0), (ubig!(1) << 100, ubig!(1) << 101, 0), (ubig!(1) << 1000, ubig!(1) << 1001, 0), // small bases (ubig!(4), ubig!(3), 1), (ubig!(10), ubig!(3), 2), (ubig!(1) << 20, ubig!(3), 12), (ubig!(1) << 50, ubig!(3), 31), (ubig!(1) << 100, ubig!(3), 63), (ubig!(1) << 500, ubig!(3), 315), (ubig!(1) << 5000, ubig!(3), 3154), (ubig!(1) << 20, ubig!(10), 6), (ubig!(1) << 50, ubig!(10), 15), (ubig!(1) << 100, ubig!(10), 30), (ubig!(1) << 500, ubig!(10), 150), (ubig!(1) << 5000, ubig!(10), 1505), ((ubig!(1) << 20) - 1u8, ubig!(31), 4), ((ubig!(1) << 50) - 1u8, ubig!(31), 10), ((ubig!(1) << 100) - 1u8, ubig!(31), 20), ((ubig!(1) << 500) - 1u8, ubig!(31), 100), ((ubig!(1) << 5000) - 1u8, ubig!(31), 1009), (ubig!(7).pow(11) - 1u8, ubig!(7), 10), (ubig!(7).pow(20), ubig!(3).pow(20) + 2u8, 1), (ubig!(7).pow(200), ubig!(3).pow(20) + 2u8, 17), (ubig!(7).pow(2000), ubig!(3).pow(20) + 2u8, 177), (ubig!(7).pow(40), ubig!(3).pow(40) + 2u8, 1), (ubig!(7).pow(400), ubig!(3).pow(40) + 2u8, 17), (ubig!(7).pow(4000), ubig!(3).pow(40) + 2u8, 177), // large bases (ubig!(2).pow(4000), ubig!(2).pow(400), 10), (ubig!(3).pow(4000), ubig!(2).pow(400), 15), (ubig!(5).pow(4000), ubig!(2).pow(400), 23), (ubig!(7).pow(4000), ubig!(2).pow(400), 28), (ubig!(3).pow(4000), ubig!(3).pow(400), 10), (ubig!(5).pow(4000), ubig!(3).pow(400), 14), (ubig!(7).pow(4000), ubig!(3).pow(400), 17), (ubig!(5).pow(4000), ubig!(5).pow(400), 10), (ubig!(7).pow(4000), ubig!(5).pow(400), 12), (ubig!(7).pow(4000), ubig!(7).pow(400), 10), // large bases with near perfect power (ubig!(2).pow(4000) - 1u8, ubig!(2).pow(400), 9), (ubig!(3).pow(4000) - 1u8, ubig!(3).pow(400), 9), (ubig!(5).pow(4000) - 1u8, ubig!(5).pow(400), 9), (ubig!(7).pow(4000) - 1u8, ubig!(7).pow(400), 9), (ubig!(2).pow(4000) + 1u8, ubig!(2).pow(400), 10), (ubig!(3).pow(4000) + 1u8, ubig!(3).pow(400), 10), (ubig!(5).pow(4000) + 1u8, ubig!(5).pow(400), 10), (ubig!(7).pow(4000) + 1u8, ubig!(7).pow(400), 10), ]; for (pow, base, exp) in test_cases { assert_eq!(pow.ilog(&base), exp, "{}, {}, {}", pow, base, exp); } } #[test] fn test_log2_ubig() { // log2 should be exact when the result is an inlined integer for i in [0, 1, 2, 4, 10, 31] { let (lb, ub) = ubig!(2).pow(i).log2_bounds(); assert_eq!(lb, i as f32); assert_eq!(ub, i as f32); } let test_cases = [ (ubig!(3), 1.584962500721156), (ubig!(5), 2.321928094887362), (ubig!(7), 2.807354922057604), (ubig!(10), core::f64::consts::LOG2_10), ((ubig!(1) << 8) - 1u8, 7.994353436858858), ((ubig!(1) << 16) - 1u8, 15.999977986052736), ((ubig!(1) << 16) - (ubig!(1) << 11), 15.954196310386875), ((ubig!(1) << 32) - 1u8, 31.999999999664098), ((ubig!(1) << 32) - (ubig!(1) << 22), 31.998590429745327), (ubig!(1) << 50, 50.), (ubig!(1) << 100, 100.), (ubig!(1) << 5000, 5000.), (ubig!(3).pow(5), 7.924812503605781), (ubig!(5).pow(7), 16.253496664211536), (ubig!(7).pow(11), 30.880904142633646), (ubig!(3).pow(4000), 6339.850002884625), (ubig!(5).pow(4000), 9287.71237954945), (ubig!(7).pow(4000), 11229.419688230417), (ubig!(10).pow(4000), 13287.71237954945), (ubig!(10).pow(100000), 332192.8094887362), ]; const ERR_BOUND: f64 = 1. / 256.; for (n, log2) in test_cases { let (lb, ub) = n.log2_bounds(); let (lb, ub) = (lb as f64, ub as f64); assert!(lb <= log2 && (log2 - lb) / log2 < ERR_BOUND); assert!(ub >= log2 && (ub - log2) / log2 < ERR_BOUND); } } #[test] #[should_panic] fn test_log_base_0() { let _ = ubig!(1234).ilog(&ubig!(0)); } #[test] #[should_panic] fn test_log_base_1() { let _ = ubig!(1234).ilog(&ubig!(1)); } #[test] #[should_panic] fn test_log_0() { let _ = ubig!(0).ilog(&ubig!(1234)); }