23
\$\begingroup\$

A prime power is a positive integer n that can be written in the form n = pk where p is a prime and k is a positive integer. For example, some prime powers are [2, 3, 5, 4, 9, 25, 8, 27, 125].

Next, consider prime powers of 2. These are [2, 4, 8, 16, ...] and can be written in the form 2k. They would all be included when considering prime powers beneath 20. However, 16 is the maximal prime power with a base prime of 2 in that range. A prime power pk is maximal in a range if it is the highest power of p in that range. We are only interested in the maximal prime power in each range so all lower prime powers must be excluded.

Your goal is to write a function or program that takes a positive integer n and outputs the maximal prime powers in the range [2, 3, 4, ..., n].

Thanks to @Peter Taylor for clarifying the definition of maximal prime power and more.

Rules

  • This is so make your code as short as possible.
  • The maximal prime powers may be output in any order but there must be no duplicates.

Test cases

n      result
1      []
2      [2]
3      [2, 3]
4      [3, 4]
5      [3, 4, 5]
6      [3, 4, 5]
7      [3, 4, 5, 7]
20     [5, 7, 9, 11, 13, 16, 17, 19]
50     [11, 13, 17, 19, 23, 25, 27, 29, 31, 32, 37, 41, 43, 47, 49]
100    [11, 13, 17, 19, 23, 25, 29, 31, 37, 41, 43, 47, 49, 53, 59, 61, 64, 67, 71, 73, 79, 81, 83, 89, 97]
10000  <1229 results>
       [101, 103, 107, 109, 113, 127, 131, 137, 139, 149, ..., 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973]

The full list of maximal prime powers for 10000 can be found here.

\$\endgroup\$

20 Answers 20

16
\$\begingroup\$

Jelly, 7 4 bytes

æḟÆR

Try it online!

How it works

æḟÆR  Main link. Argument: n

  ÆR  Prime range; yield all primes in [1, ..., n].
æḟ    Power floor; round n down to the nearest power of each prime in the range.
\$\endgroup\$
  • \$\begingroup\$ Oh so obvious once one sees it! \$\endgroup\$ – Jonathan Allan Feb 7 '17 at 0:48
  • 15
    \$\begingroup\$ Power floor What the heck \$\endgroup\$ – JungHwan Min Feb 7 '17 at 6:22
  • 1
    \$\begingroup\$ This post officially convinced me to learn Jelly. \$\endgroup\$ – Chandler Watson Feb 7 '17 at 6:44
10
\$\begingroup\$

Mathematica, 44 43 40 bytes

Saved 4 bytes thanks to miles and Martin Ender

n#^⌊#~Log~n⌋&/@Select[Range@n,PrimeQ]

(x=Prime@Range@PrimePi@#)^⌊x~Log~#⌋&

and are the 3 byte characters U+230A and U+230B representing \[LeftFloor] and \[RightFloor], respectively.

Explanation:

enter image description here

Pure function. # is short for Slot[1] which represents the first argument to the Function. PrimePi@# counts the number of primes less or equal to #, Range@PrimePi@# is the list of the first PrimePi[#] positive integers, and so Prime@Range@PrimePi@# is the list of primes less than or equal to # (this is one byte shorter than Select[Range@#,PrimeQ]). The symbol x is Set equal to this list, then raised to the Power ⌊x~Log~#⌋, which is the list of Floor[Log[n,#]] for each n in x. In Mathematica, raising a list to the Power of another list of the same length results in the list of the powers of their corresponding elements.

\$\endgroup\$
  • \$\begingroup\$ I thought Range@#~Select~PrimeQ would be shorter than Prime@Range@PrimePi@# ... but it's a tie \$\endgroup\$ – Greg Martin Feb 6 '17 at 20:08
  • \$\begingroup\$ That's a nice figure. Was it generated using a builtin or created manually? \$\endgroup\$ – miles Feb 6 '17 at 21:00
  • \$\begingroup\$ @miles It was generated using TreeForm \$\endgroup\$ – ngenisis Feb 6 '17 at 21:01
  • \$\begingroup\$ Thanks. I don't remember ever seeing it, but evidently it's been around forever. \$\endgroup\$ – miles Feb 6 '17 at 21:04
7
\$\begingroup\$

MATL, 13 bytes

ZqG:!^tG>~*X>

Try it Online!

Explanation

        % Implicitly grab the input as a number (N)
Zq      % Get an array of all primes below N
G:!     % Create an array from [1...N]
^       % Raise each prime to each power in this array which creates a 2D matrix
        % where the powers of each prime are down the columns
tG>~    % Create a logical matrix that is TRUE where the values are less than N
*       % Perform element-wise multiplication to force values > N to zero
X>      % Compute the maximum value of each column
        % Implicitly display the resulting array
\$\endgroup\$
7
\$\begingroup\$

Jelly, 8 bytes

ÆR*ÆE€»/

Try it online!

How it works

ÆR*ÆE€»/  Main link. Argument: n

ÆR        Prime range; yield all primes in [1, ..., n].
   ÆE€    Prime exponents each; yield the exponents of 2, 3, 5, ... of the prime
          factorization of each k in [1, ..., n].
          For example, 28 = 2² × 3⁰ × 5⁰ × 7¹ yields [2, 0, 0, 1].
  *       Exponentiation; raise the elements of the prime range to the powers
          of each of the exponents arrays.
      »/  Reduce the columns by maximum.
\$\endgroup\$
6
\$\begingroup\$

Jelly, 12 9 bytes

RÆEz0iṀ$€

Try it online! (method is too slow for the 10000 case).

How?

Builds the list of pk in order of p.

RÆEz0iṀ$€ - Main link: n                      e.g. 7
R         - range(n)                          [1 ,2  ,3    ,4  ,5      ,6    ,7]
 ÆE       - prime factor vector (vectorises)  [[],[1],[0,1],[2],[0,0,1],[1,1],[0,0,0,1]]
   z0     - transpose with filler 0           [[0,1,0,2,0,1,0],[0,0,1,0,0,1,0],[0,0,0,0,1,0,0],[0,0,0,0,0,0,1]]
       $€ - la$t two links as a monad, for €ach       ^             ^                   ^                   ^
     i    -     first index of                        4             3                   5                   7
      Ṁ   -     maximum                       [4,3,5,7]
\$\endgroup\$
5
\$\begingroup\$

Pyth, 13 bytes

m^ds.lQdfP_TS

Try it here!

        f   S -  filter(v, range(1, input))
         P_T  -   is_prime(T)
m             - map(v, ^)
    .lQd      -    log(input, d)
   s          -   int(^)
 ^d           -  d ** ^

I haven't played with Pyth in a while so any golfing tips are appreciated.

\$\endgroup\$
5
\$\begingroup\$

I couldn't get a shorter Mathematica solution than ngenisis's solution, but I thought I'd offer a couple of (hopefully interesting) alternative approaches.

Mathematica, 65 bytes

#/#2&@@@({#,#}&/@Range@#~Select~PrimeQ//.{a_,b_}/;a<=#:>{b a,b})&

First we use {#,#}&/@Range@#~Select~PrimeQ to build a list of all primes in the appropriate range, but with ordered pairs of each prime, like { {2,2}, {3,3}, ...}. Then we operate on that list repeatedly with the replacement rule {a_,b_}/;a<=#:>{b a,b}, which multiplies the first element of the ordered pair by the second until the first element exceeds the input. Then we apply #/#2&@@@ to output, for each ordered pair, the first element divided by the second. (They end up sorted by the underlying prime: an example output is {16, 9, 5, 7, 11, 13, 17, 19}.)

Mathematica, 44 bytes

Values@Rest@<|MangoldtLambda@#->#&~Array~#|>&

The von Mangoldt function Λ(n) is an interesting number theory function: it equals 0 unless n is a prime power pk, in which case it equals log p (not log n). (These are natural logs, but it won't matter.) Thus MangoldtLambda@#->#&~Array~# creates an array of rules { 0->1, Log[2]->2, Log[3]->3, Log[2]->4, Log[5]->5, 0->6, ... } whose length is the input integer.

We then turn this list of rules into an "association" using <|...|>. This has the effect of retaining only the last rule with any given left-hand value. In other words, it will throw away Log[2]->2 and Log[2]->4 and Log[2]->8 and keep only Log[2]->16 (assuming that the input is between 16 and 31 for this example). Therefore the only remaining right-hand sides are the maximal prime powers—except for the one remaining rule 0->n, where n is the largest non-prime-power up to the input integer. But Rest throws that undesired rule away, and Values extracts the right-hand sides from the rules in the association. (They end up sorted as above.)

A slightly longer (46 bytes) version, which counts the number of appearances of each log p and then exponentiates to convert to the maximal prime powers:

E^(1##)&@@@Rest@Tally[MangoldtLambda~Array~#]&
\$\endgroup\$
  • 1
    \$\begingroup\$ Neat use of associations. They've been out since 2014 but I don't think they've seen much use in golfing. Very useful to know it replaces identical keys with values from left to right. \$\endgroup\$ – miles Feb 6 '17 at 21:16
4
\$\begingroup\$

CJam, 21 20 bytes

Saved 1 byte thanks to Martin Ender

ri_){mp},f{\1$mLi#}p

Try it online!

Explanation

ri                    e# Read an integer from input (let's call it n)
  _                   e# Duplicate it
   ){mp},             e# Push the array of all prime numbers up to and including n
         f{           e# Map the following block to each prime p:
           \          e#   Swap the top two elements of the stack
            1$        e#   Copy the second element down in the stack. Stack is now [p n p]
              mL      e#   Take the base-p logatithm of n
                i     e#   Cast to int (floor)
                 #    e#   Raise p to that power
                  }   e# (end of map block)
                   p  e# Print
\$\endgroup\$
4
\$\begingroup\$

Brachylog, 15 bytes

⟧{ḋ=}ˢ⊇Xhᵐ≠∧X×ᵐ

Try it online!

This outputs the powers from biggest to smallest.

This is very inefficient.

Explanation

⟧                   The Range [Input, Input - 1, ..., 1, 0]
 {  }ˢ              Select:
  ḋ=                  The elements of that range whose prime decompositions are lists of the
                      same element (e.g. [3,3,3]); output is those prime decompositions
      ⊇X            X is an ordered subset of that list of prime decompositions
       Xhᵐ≠         All first elements of the prime decompositions are different (that is,
                      X contains prime decompositions with different primes each times)
           ∧
            X×ᵐ     Output is the result of mapping multiplication to each element of X

This will find the biggest prime decompositions for each prime first because of the way works: from left to right and from biggest to smallest subsets.

\$\endgroup\$
4
\$\begingroup\$

Brachylog, 24 21 19 bytes

3+2 bytes saved thanks to Fatalize!

This is my first time using Brachylog, and I know some things could have been done in shorter ways, but I'm happy that it even works :D

{≥.~^ℕ₁ᵐhṗ:.≜×>?∧}ᶠ

Try it online! (Return values are ordered by their base primes)

Explanation:

{................}ᶠ           #Find all possible results of what's inside.
 ≥.                           #Input is >= than the output.
  .~^ℕ₁ᵐ                      #Output can be calculated as A^B, where A and B are
                              #Natural numbers >=1.
        hṗ                    #The first of those numbers (A) is prime
          :.≜×>?              #That same element (A), multiplied by the output
                              #is greater than the input - This means 
                              #that B is the maximal exponent for A.
                ∧             #No more restrictions on the output.
\$\endgroup\$
  • 1
    \$\begingroup\$ Great! You can save two bytes by using the specific variable names ? and . for Input and Output, instead of I and X, as such: {≥N~^.hṗ:N×>?∧0<~t}ᶠ^ᵐ \$\endgroup\$ – Fatalize Feb 8 '17 at 9:43
  • 1
    \$\begingroup\$ You can also save another byte by removing 0<~t and stating that each element of the Output . is in ℕ₁ = [1, ..., +inf) as such: {≥N~^.ℕ₁ᵐhṗ:N×>?∧}ᶠ^ᵐ \$\endgroup\$ – Fatalize Feb 8 '17 at 9:56
  • \$\begingroup\$ @Fatalize thank you! I'll update the solution with your suggestions :) By the way, do you know why a solution like {≥.~^ℕ₁ᵐhṗ:.×>?∧}ᶠ (using N directly as output) doesn't work? I tried first something like this, but then had to resort to using X and applying ^ over it \$\endgroup\$ – Leo Feb 8 '17 at 10:34
  • 2
    \$\begingroup\$ I actually wondered the same thing; this is possibly due to the implicit labelization step that occurs at the end of the predicate in {...}ᶠ which causes weird behavior. I intend to change that and I will look specifically into why this program does not work the same way as the one above. \$\endgroup\$ – Fatalize Feb 8 '17 at 10:51
  • 1
    \$\begingroup\$ It actually works if you do it like this: {≥.~^ℕ₁ᵐhṗ:.≜×>?∧}ᶠ That way you get correct labelization. (A change was made to the specs in the meantime but does not actually change the behavior of this particular program, so it does not make it non-competing). This saves 2 bytes \$\endgroup\$ – Fatalize Feb 8 '17 at 15:01
3
\$\begingroup\$

05AB1E, 15 12 bytes

ƒNpiN¹N.nïm,

Try it online!

Explanation

ƒ             # for N in [0 ... input]
 Npi          # if N is prime
    N         # push N
     ¹N.n     # push log_N(input)
         ï    # convert to int
          m   # raise N to this power
           ,  # print
\$\endgroup\$
3
\$\begingroup\$

Bash + GNU utilities, 74 bytes

seq $1|factor|sed "s@.*: \(\w*\)\$@\1;l($1);l(\1);print \"/^p\"@"|bc -l|dc

Try it online!

The input number is passed as an argument. The output is printed to stdout. (As is customary, stderr is ignored.)

Sample output:

./maximalprimepowers 100 2>/dev/null
64
81
25
49
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97

./maximalprimepowers 10000 2>/dev/null | wc -l
1229

Here's how it works:

Call the argument N.

seq generates all the numbers from 1 to N, and factor factors them all.

The regex in the call to sed identifies those lines where the number is a prime P, and replaces those lines with lines that are of the form `

P;l(N);l(P);print "/^p"

(where P and N are replaced by their actual numerical values, and everything else is copied literally, even the quotes and semicolons, and the string print).

These lines are fed as input to bc -l; bc prints the values of the three indicated numbers, each followed by a newline, and then prints the characters /^p . (In bc, l(x) denotes the natural logarithm of x.) JK K

The strings that bc prints are then fed as input to dc; dc prints the value of each P^(log(N)/log(P)) using integer arithmetic (truncating); that's the greatest power of P that is <= N.

One thing that's glossed over above is what happens to lines that are produced by factors that don't correspond to primes. Those lines don't match the regex in the call to sed, so no replacement is done on those. As a result, those lines start with a number followed by a colon, which generates an error when fed as input to bc. But bc just prints to stderr then, which we ignore; it doesn't print anything to stdout. By default, stderr is ignored on PPCG.

\$\endgroup\$
3
\$\begingroup\$

Haskell, 73 67 66 bytes

p n=[last[x^i|i<-[1..n],x^i<=n]|x<-[2..n],all((>0).mod x)[2..x-1]]

Try it online! Usage:

Prelude> p 50
[32,27,25,49,11,13,17,19,23,29,31,37,41,43,47]

Edit: 6 bytes off thanks to Zgarb!

Explanation:

p n=[... x|x<-[2..n]                         ] -- list of all x in the range 2 to n
p n=[... x|x<-[2..n],        mod x<$>[2..x-1]] -- where the remainders of x mod the numbers 2 to x-1
p n=[... x|x<-[2..n],all(>0)$mod x<$>[2..x-1]] -- are all greater 0. This yields all primes in the range.

p n=[    [x^i|i<-[1..n]       ]|...] -- for each of those x generate the list of all x^i with i in the range 1 to n
p n=[last[x^i|i<-[1..n],x^i<=n]|...] -- where x^i is smaller or equal to n
p n=[last[x^i|i<-[1..n],x^i<=n]|...] -- and take the last (that is the largest) element
\$\endgroup\$
  • 1
    \$\begingroup\$ I think the left side can be last[x^i|i<-[1..n],x^i<=n]. \$\endgroup\$ – Zgarb Feb 10 '17 at 13:44
  • \$\begingroup\$ @Zgarb Thanks! It's always the list comprehensions, isn't it ... \$\endgroup\$ – Laikoni Feb 10 '17 at 14:24
2
\$\begingroup\$

Jelly, 9 bytes

Ræl/ÆF*/€

One byte longer than my other answer, but finishes for input 10,000 is a couple of seconds.

Try it online!

How it works

Ræl/ÆF*/€  Main link. Argument: n

R          Range; yield [1, ..., n].
 æl/       Reduce by least common multiple.
    ÆF     Factor the LCM into [prime, exponent] pairs.
      */€  Reduce each pair by exponentiation.
\$\endgroup\$
  • \$\begingroup\$ There is also a 7 byte version in Jelly that finishes quickly. \$\endgroup\$ – miles Feb 7 '17 at 0:13
  • \$\begingroup\$ I'll see your 7 and raise you 4. :P \$\endgroup\$ – Dennis Feb 7 '17 at 0:42
  • \$\begingroup\$ Wow, I did not know that was a builtin too. That takes the cake. \$\endgroup\$ – miles Feb 7 '17 at 0:47
2
\$\begingroup\$

JavaScript (ES6), 118 120 119 114 112 105 bytes

(n,r)=>(r=k=>[...Array(k-1)].map((_,i)=>i+2),r(n).filter(q=>r(q).every(d=>q%d|!(d%(q/d)*(q/d)%d)&q*d>n)))

Suggestions welcome. This is kind of long, but it seemed worth posting because it does all the divisibility testing explicitly rather than using built-ins related to primes.

Notes:

  • A natural number q is a prime power <=> all of q's divisors are powers of the same prime <=> for any d which divides q, one of d and q/d is a divisor of the other.
  • If q is a power of p, q is maximal <=> q * p > n <=> q * d > n for every nontrivial divisor d of q.
\$\endgroup\$
2
\$\begingroup\$

Sage, 43 bytes

lambda i:[x^int(ln(i,x))for x in primes(i)]

Maps each prime in the range primes(i) to its maximal prime power. ln is just an alias of log so it accepts alternate bases although its name suggests it can only use base e.

\$\endgroup\$
  • \$\begingroup\$ Thought this was python at first, saw the primes function and got really excited. Never trusting stackoverflow again. \$\endgroup\$ – sagiksp Feb 19 '17 at 10:59
  • \$\begingroup\$ @sagiksp I don't get it, what does it have to do with StackOverflow? \$\endgroup\$ – busukxuan Feb 19 '17 at 11:01
2
\$\begingroup\$

Haskell, 110 90 bytes

s[]=[];s(x:t)=x:s[y|y<-t,y`rem`x>0];f n=[last.fst.span(<=n).scanl1(*)$repeat x|x<-s[2..n]]

--updated per Laikoni's feedback

\$\endgroup\$
  • \$\begingroup\$ This throws a Exception: Prelude.last: empty list for f 2 and f 3. \$\endgroup\$ – Laikoni Feb 8 '17 at 17:18
  • 1
    \$\begingroup\$ Also f 4 returns [2,3] instead of [4,3], I think your takeWhile(<n) needs to be takeWhile(<=n). However using fst.span instead of takeWhile is one byte shorter. \$\endgroup\$ – Laikoni Feb 8 '17 at 17:20
2
\$\begingroup\$

Haskell, 70 bytes

f n=[k|k<-[2..n],p:q<-[[d|d<-[2..k],mod k d<1]],k==p*p^length q,p*k>n]

Defines a function f. Try it online!

Explanation

The idea is to filter the range [2..n] for those numbers k that satisfy k == p^length(divisors k) and p*k > n, where p is the smallest prime divisor of k.

f n=                -- Define f n as
 [k|                -- the list of numbers k, where
  k<-[2..n],        -- k is drawn from [2..n],
  p:q<-[            -- the list p:q is drawn from
   [d|              -- those lists of numbers d where
    d<-[2..k],      -- d is drawn from [2..k] and
    mod k d<1]      -- d divides k
   ],               -- (so p:q are the divisors of k except 1, and p is the smallest one),
  k==p*p^length q,  -- k equals p to the power of the divisor list's length
                    -- (so it's in particular a prime power), and
  p*k>n]            -- p*k, the next power of p, is not in the range [2..n].
\$\endgroup\$
1
\$\begingroup\$

PHP, 101 93 91 88 bytes

just a little bit of real maths ...

for($n=$argv[$i=1];$n>$j=$i++;$j?:$r[$p=$i**~~log($n,$i)]=$p)for(;$i%$j--;);print_r($r);

breakdown

for($n=$argv[$i=1];     // loop $i from 2 to $n
    $n>$j=$i++;             // 0.: init $j to $i-1
    $j?:                    // 2. if $i is prime
        $r[$p=$i**~~log($n,$i)]=$p) // 3. add maximum power to results
    for(;$i%$j--;);         // 1. prime check (if $i is prime, $j will be 0)
print_r($r);            // print results
\$\endgroup\$
1
\$\begingroup\$

JavaScript ES7, 93 bytes

Recursively iterate i from 0 up to and including n. If i is prime raise it to the highest floored exponent that makes it <= n (i ^ floor(log(n) / log(i)))

F=(n,i=n)=>i?[...((P=j=>i%--j?P(j):1==j)(i)?[i**((l=Math.log)(n)/l(i)|0)]:[]),...F(n,--i)]:[]
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.