is_omega_prime.pl 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #!/usr/bin/perl
  2. # Author: Trizen
  3. # Date: 17 February 2023
  4. # https://github.com/trizen
  5. # A simple and fast method for checking if a given integer n has exactly k distinct prime factors (i.e.: omega(n) = k).
  6. use 5.020;
  7. use warnings;
  8. use ntheory qw(:all);
  9. use experimental qw(signatures);
  10. use Math::GMPz;
  11. use Math::Prime::Util::GMP;
  12. use constant {
  13. TRIAL_LIMIT => 1e3,
  14. HAS_NEW_PRIME_UTIL => defined(&Math::Prime::Util::is_omega_prime),
  15. };
  16. my @SMALL_PRIMES = @{primes(TRIAL_LIMIT)};
  17. sub mpz_is_omega_prime ($n, $k) {
  18. state $z = Math::GMPz::Rmpz_init();
  19. state $t = Math::GMPz::Rmpz_init();
  20. if ($n == 0) {
  21. return 0;
  22. }
  23. Math::GMPz::Rmpz_set_str($z, "$n", 10);
  24. Math::GMPz::Rmpz_root($t, $z, $k);
  25. my $trial_limit = Math::GMPz::Rmpz_get_ui($t);
  26. if ($trial_limit > TRIAL_LIMIT or !Math::GMPz::Rmpz_fits_ulong_p($t)) {
  27. $trial_limit = TRIAL_LIMIT;
  28. }
  29. foreach my $p (@SMALL_PRIMES) {
  30. last if ($p > $trial_limit);
  31. if (Math::GMPz::Rmpz_divisible_ui_p($z, $p)) {
  32. --$k;
  33. Math::GMPz::Rmpz_set_ui($t, $p);
  34. Math::GMPz::Rmpz_remove($z, $z, $t);
  35. }
  36. ($k > 0) or last;
  37. if (HAS_NEW_PRIME_UTIL and Math::GMPz::Rmpz_fits_ulong_p($z)) {
  38. return Math::Prime::Util::is_omega_prime($k, Math::GMPz::Rmpz_get_ui($z));
  39. }
  40. }
  41. if (Math::GMPz::Rmpz_cmp_ui($z, 1) == 0) {
  42. return ($k == 0);
  43. }
  44. if ($k == 0) {
  45. return (Math::GMPz::Rmpz_cmp_ui($z, 1) == 0);
  46. }
  47. if ($k == 1) {
  48. if (Math::GMPz::Rmpz_fits_ulong_p($z)) {
  49. return is_prime_power(Math::GMPz::Rmpz_get_ui($z));
  50. }
  51. return Math::Prime::Util::GMP::is_prime_power(Math::GMPz::Rmpz_get_str($z, 10));
  52. }
  53. Math::GMPz::Rmpz_ui_pow_ui($t, next_prime($trial_limit), $k);
  54. if (Math::GMPz::Rmpz_cmp($z, $t) < 0) {
  55. return 0;
  56. }
  57. (HAS_NEW_PRIME_UTIL and Math::GMPz::Rmpz_fits_ulong_p($z))
  58. ? Math::Prime::Util::is_omega_prime($k, Math::GMPz::Rmpz_get_ui($z))
  59. : (factor_exp(Math::GMPz::Rmpz_get_str($z, 10)) == $k);
  60. }
  61. foreach my $n (1 .. 100) {
  62. my $t = urandomb($n) + 1;
  63. say "Testing: $t";
  64. foreach my $k (1 .. 20) {
  65. if (HAS_NEW_PRIME_UTIL ? Math::Prime::Util::is_omega_prime($k, $t) : (factor_exp($t) == $k)) {
  66. mpz_is_omega_prime($t, $k) || die "error for: ($t, $k)";
  67. }
  68. elsif (mpz_is_omega_prime($t, $k)) {
  69. die "counter-example: ($t, $k)";
  70. }
  71. }
  72. }