1use super::Z;
12use crate::rational::Q;
13use flint_sys::{
14 fmpq::{fmpq, fmpq_inv},
15 fmpz::{
16 fmpz, fmpz_abs, fmpz_bits, fmpz_is_one, fmpz_is_perfect_power, fmpz_is_prime, fmpz_is_zero,
17 fmpz_tstbit,
18 },
19};
20
21impl Z {
22 pub fn is_zero(&self) -> bool {
34 1 == unsafe { fmpz_is_zero(&self.value) }
35 }
36
37 pub fn is_one(&self) -> bool {
49 1 == unsafe { fmpz_is_one(&self.value) }
50 }
51
52 pub fn is_prime(&self) -> bool {
64 1 == unsafe { fmpz_is_prime(&self.value) }
65 }
66
67 pub fn abs(mut self) -> Self {
79 unsafe {
80 fmpz_abs(&mut self.value, &self.value);
81 }
82 self
83 }
84
85 pub fn inverse(&self) -> Option<Q> {
99 if self == &Z::ZERO {
100 return None;
101 }
102
103 let mut out = Q::ZERO;
104 let self_fmpq = fmpq {
109 num: self.value,
110 den: fmpz(1),
111 };
112 unsafe { fmpq_inv(&mut out.value, &self_fmpq) };
113 Some(out)
114 }
115
116 pub fn bits(&self) -> u64 {
132 unsafe { fmpz_bits(&self.value) }
133 }
134
135 pub fn to_bits(&self) -> Vec<bool> {
150 let value = self.clone().abs();
152 let mut bits = Vec::with_capacity(value.bits() as usize);
154 for i in 0..value.bits() {
155 let bit_i = unsafe { fmpz_tstbit(&value.value, i) };
157 if bit_i == 0 {
159 bits.push(false);
160 } else {
161 bits.push(true);
162 }
163 }
164
165 bits
166 }
167
168 pub fn is_perfect_power(&self) -> Option<(Self, i32)> {
188 let mut root = Z::default();
189 let exp = unsafe { fmpz_is_perfect_power(&mut root.value, &self.value) };
190 if root.is_zero() && exp == 0 {
191 return None;
192 }
193 Some((root, exp))
194 }
195}
196
197#[cfg(test)]
198mod test_is_perfect_power {
199 use super::Z;
200 use crate::traits::Pow;
201
202 #[test]
204 fn positive_small_2() {
205 let x = Z::from(32);
206
207 let (root, exp) = x.is_perfect_power().unwrap();
208
209 assert_eq!(root, Z::from(2));
210 assert_eq!(exp, 5);
211 }
212
213 #[test]
215 fn positive_small_5() {
216 let x = Z::from(25);
217
218 let (root, exp) = x.is_perfect_power().unwrap();
219
220 assert_eq!(root, Z::from(5));
221 assert_eq!(exp, 2);
222 }
223
224 #[test]
226 fn positive_small_non_perfect_power() {
227 let x = Z::from(26);
228
229 let result = x.is_perfect_power();
230
231 assert!(result.is_none());
232 }
233
234 #[test]
236 fn positive_large_2() {
237 let x = Z::from(i64::MAX as u64 + 1);
238
239 let (root, exp) = x.is_perfect_power().unwrap();
240
241 assert_eq!(root, Z::from(2));
242 assert_eq!(exp, 63);
243 }
244
245 #[test]
247 fn positive_large_5() {
248 let x = Z::from(5).pow(67).unwrap();
249
250 let (root, exp) = x.is_perfect_power().unwrap();
251
252 assert_eq!(root, Z::from(5));
253 assert_eq!(exp, 67);
254 }
255
256 #[test]
258 fn positive_large_25() {
259 let x = Z::from(25).pow(50).unwrap();
260
261 let (root, exp) = x.is_perfect_power().unwrap();
262
263 assert_eq!(root, Z::from(5));
264 assert_eq!(exp, 100);
265 }
266
267 #[test]
269 fn positive_large_non_perfect_power() {
270 let x = Z::from(i64::MAX);
271
272 let result = x.is_perfect_power();
273
274 assert!(result.is_none());
275 }
276
277 #[test]
279 fn zero() {
280 let x = Z::ZERO;
281
282 let (root, exp) = x.is_perfect_power().unwrap();
283
284 assert!(root.is_zero());
285 assert!(exp > 0);
286 }
287
288 #[test]
290 fn negative_small_2() {
291 let x = Z::from(-32);
292
293 let (root, exp) = x.is_perfect_power().unwrap();
294
295 assert_eq!(root, Z::from(-2));
296 assert_eq!(exp, 5);
297 }
298
299 #[test]
301 fn negative_small_5() {
302 let x = Z::from(-125);
303
304 let (root, exp) = x.is_perfect_power().unwrap();
305
306 assert_eq!(root, Z::from(-5));
307 assert_eq!(exp, 3);
308 }
309
310 #[test]
312 fn negative_small_non_perfect_power() {
313 let x = Z::from(-26);
314
315 let result = x.is_perfect_power();
316
317 assert!(result.is_none());
318 }
319
320 #[test]
322 fn negative_large_2() {
323 let x = Z::from(i64::MIN);
324
325 let (root, exp) = x.is_perfect_power().unwrap();
326
327 assert_eq!(root, Z::from(-2));
328 assert_eq!(exp, 63);
329 }
330
331 #[test]
333 fn negative_large_5() {
334 let x = Z::from(-5).pow(67).unwrap();
335
336 let (root, exp) = x.is_perfect_power().unwrap();
337
338 assert_eq!(root, Z::from(-5));
339 assert_eq!(exp, 67);
340 }
341
342 #[test]
344 fn negative_large_25() {
345 let x = Z::from(-25).pow(67).unwrap();
346
347 let (root, exp) = x.is_perfect_power().unwrap();
348
349 assert_eq!(root, Z::from(-25));
350 assert_eq!(exp, 67);
351 }
352
353 #[test]
355 fn negative_large_non_perfect_power() {
356 let x = Z::from(i64::MIN + 1);
357
358 let result = x.is_perfect_power();
359
360 assert!(result.is_none());
361 }
362}
363
364#[cfg(test)]
365mod test_to_bits {
366 use super::Z;
367
368 #[test]
370 fn positive() {
371 let value_0 = Z::from(16);
372 let value_1 = Z::from(u64::MAX);
373
374 let res_0 = value_0.to_bits();
375 let res_1 = value_1.to_bits();
376
377 assert_eq!(vec![false, false, false, false, true], res_0);
378 assert_eq!(vec![true; 64], res_1);
379 }
380
381 #[test]
383 fn zero() {
384 let value = Z::ZERO;
385 let cmp: Vec<bool> = vec![];
386
387 let res = value.to_bits();
388
389 assert_eq!(cmp, res);
390 }
391
392 #[test]
394 fn negative() {
395 let value_0 = Z::from(-13);
396 let value_1 = Z::from(i64::MIN);
397 let mut cmp = vec![false; 63];
398 cmp.push(true);
399
400 let res_0 = value_0.to_bits();
401 let res_1 = value_1.to_bits();
402
403 assert_eq!(vec![true, false, true, true], res_0);
404 assert_eq!(cmp, res_1);
405 }
406}
407
408#[cfg(test)]
409mod test_bits {
410 use super::Z;
411
412 #[test]
415 fn small_values() {
416 assert_eq!(0, Z::ZERO.bits());
417 assert_eq!(1, Z::ONE.bits());
418 assert_eq!(1, Z::MINUS_ONE.bits());
419 assert_eq!(3, Z::from(4).bits());
420 assert_eq!(31, Z::from(i32::MAX).bits());
421 assert_eq!(32, Z::from(i32::MIN).bits());
422 assert_eq!(32, Z::from(u32::MAX).bits());
423 }
424
425 #[test]
428 fn large_values() {
429 let vector = vec![255; 16];
430 let large = Z::from_bytes(&vector);
431
432 assert_eq!(128, large.bits());
433 assert_eq!(63, Z::from(i64::MAX).bits());
434 assert_eq!(64, Z::from(i64::MIN).bits());
435 assert_eq!(64, Z::from(u64::MAX).bits());
436 }
437}
438
439#[cfg(test)]
440mod test_abs {
441 use super::Z;
442
443 #[test]
445 fn small_values() {
446 let pos = Z::ONE;
447 let zero = Z::ZERO;
448 let neg = Z::from(-15);
449
450 assert_eq!(Z::ONE, pos.abs());
451 assert_eq!(Z::ZERO, zero.abs());
452 assert_eq!(Z::from(15), neg.abs());
453 }
454
455 #[test]
457 fn large_values() {
458 let pos = Z::from(i64::MAX);
459 let neg = Z::from(i64::MIN);
460
461 assert_eq!(Z::from(i64::MAX), pos.abs());
462 assert_eq!(Z::from(i64::MIN) * Z::from(-1), neg.abs());
463 }
464}
465
466#[cfg(test)]
467mod test_is_prime {
468 use super::Z;
469
470 #[test]
472 fn prime_detection() {
473 let small = Z::from(2_i32.pow(16) + 1);
474 let large = Z::from(u64::MAX - 58);
475 assert!(small.is_prime());
476 assert!(large.is_prime());
477 }
478
479 #[test]
481 fn non_prime_detection() {
482 let small = Z::from(2_i32.pow(16));
483 let large = Z::from(i64::MAX);
484 assert!(!small.is_prime());
485 assert!(!large.is_prime());
486 }
487}
488
489#[cfg(test)]
490mod test_inv {
491 use super::{Q, Z};
492
493 #[test]
495 fn small_values() {
496 let val_0 = Z::from(4);
497 let val_1 = Z::from(-7);
498
499 let inv_0 = val_0.inverse().unwrap();
500 let inv_1 = val_1.inverse().unwrap();
501
502 assert_eq!(Q::from((1, 4)), inv_0);
503 assert_eq!(Q::from((-1, 7)), inv_1);
504 }
505
506 #[test]
508 fn large_values() {
509 let val_0 = Z::from(i64::MAX);
510 let val_1 = Z::from(i64::MIN);
511
512 let inv_0 = val_0.inverse().unwrap();
513 let inv_1 = val_1.inverse().unwrap();
514
515 assert_eq!(Q::from((1, i64::MAX)), inv_0);
516 assert_eq!(Q::from((1, i64::MIN)), inv_1);
517 }
518
519 #[test]
521 fn inv_zero_none() {
522 let zero = Z::ZERO;
523
524 let inv_zero = zero.inverse();
525
526 assert!(inv_zero.is_none());
527 }
528}
529
530#[cfg(test)]
531mod test_is_zero {
532 use super::Z;
533 use std::str::FromStr;
534
535 #[test]
537 fn zero_detection() {
538 let zero = Z::ZERO;
539
540 assert!(zero.is_zero());
541 }
542
543 #[test]
545 fn zero_rejection() {
546 let small = Z::from(2);
547 let large = Z::from_str(&format!("{}", (u128::MAX - 1) / 2 + 1)).unwrap();
548
549 assert!(!small.is_zero());
550 assert!(!large.is_zero());
551 }
552}
553
554#[cfg(test)]
555mod test_is_one {
556 use super::Z;
557 use std::str::FromStr;
558
559 #[test]
561 fn one_detection() {
562 let zero = Z::ONE;
563
564 assert!(zero.is_one());
565 }
566
567 #[test]
569 fn one_rejection() {
570 let small = Z::from(2);
571 let large = Z::from_str(&format!("{}", (u128::MAX - 1) / 2 + 2)).unwrap();
572
573 assert!(!small.is_one());
574 assert!(!large.is_one());
575 }
576}