14
\$\begingroup\$

Inspired by digital roots, the prime factoral root of a number is the number that emerges when you take the prime factors of a number, add them together, and repeat the process on the resulting number, continuing until you end up with a prime number (which has itself as its only prime factor, and is thus its own prime factoral root). The prime factoral root of 4 is 4, as 2*2=2+2, and this is the only non-prime prime factoral root of an integer greater than 1 (which is another special case, as it has no prime factors). The OEIS sequence formed by prime factoral roots is A029908.

For example, the prime factoral root of 24 is:

24=2*2*2*3

2+2+2+3=9=3*3

3+3=6=2*3

2+3=5, and the only prime factor of 5 is 5.  Therefore, the prime factoral root of 24 is 5.  

Your Task:

Write a program or function that finds the prime factoral root of an input integer.

Input:

An integer, input through any reasonable method, between 2 and the largest integer your language will support (inclusive). Specifically choosing a language that has an unreasonably low maximum integer size is not allowed (and also violates this standard loophole)

Output:

An integer, the prime factoral root of the input.

Test Cases:

4   -> 4
24  -> 5
11  -> 11
250 -> 17

Scoring:

This is , lowest score in bytes wins!

\$\endgroup\$
  • 3
    \$\begingroup\$ Can you add 4 in the test cases, since it's an exception and it's easy to forget about it while testing an answer? \$\endgroup\$ – scottinet Oct 4 '17 at 11:26
  • \$\begingroup\$ Do we have to output 1 for 1? \$\endgroup\$ – someone Oct 4 '17 at 11:36
  • \$\begingroup\$ @someone according to the linked OEIS sequence, it should output 0 for 1 \$\endgroup\$ – scottinet Oct 4 '17 at 11:55
  • 2
    \$\begingroup\$ @someone The challenge states that the input will be at least 2. \$\endgroup\$ – Martin Ender Oct 4 '17 at 13:21
  • \$\begingroup\$ @someone Sorry for being off for a while. As Martin said, the challenge specifically says that the input will be greater than one, and therefore behavior when the input is 1 is undefined. \$\endgroup\$ – Gryphon Oct 5 '17 at 1:18

18 Answers 18

15
\$\begingroup\$

05AB1E, 3 bytes

FÒO

Try it online!

Explanations:

FÒO   
F    Loops <input> times + 1
 Ò   List of prime factors w/ duplicates
  O  Total sum of the list
     -- implicit output
\$\endgroup\$
  • \$\begingroup\$ This seems to fail for 4. \$\endgroup\$ – Shaggy Oct 4 '17 at 11:09
  • 1
    \$\begingroup\$ @Shaggy fixed while saving 2 bytes \$\endgroup\$ – scottinet Oct 4 '17 at 11:21
  • 10
    \$\begingroup\$ Does this make anyone trying to beat this a FÒO-fighter? \$\endgroup\$ – steenbergh Oct 4 '17 at 14:57
  • \$\begingroup\$ At least it wasn't FOObar. \$\endgroup\$ – Magic Octopus Urn Oct 4 '17 at 18:03
14
\$\begingroup\$

Haskell, 61 bytes

import Data.Numbers.Primes
until=<<((==)=<<)$sum.primeFactors

Try it online!

Explanation

until=<<((==)=<<) takes a function f and applies it to input x until a fix point is reached, that is f x equals x. primeFactors returns the list of prime factors of a number, sum yields the sum of a list of numbers.

But wait, why does until=<<((==)=<<) the job and looks so weird?

If we assume f=sum.primeFactors, a more natural definition would be until(\x->f x==x)f, because until takes a predicate (a function which returns a boolean), a function which has the same input and return type (e.g. Int -> Int) and value of this type, and then applies the function to the value until the predicate is fulfilled.

until(\x->f x==x)f is the same as until(\x->(==)(f x)x)f, and as it holds that g (h x) x is the same as (g=<<h)x, we get until(\x->((==)=<<f)x)f. After Eta conversion, this becomes until((==)=<<f)f. But if we now treat (==)=<< as a function which is applied to f, we can see that until(((==)=<<)f)f is again of the form g (h x) x, with g=until, h=((==)=<<) and x=f, so it can be rewritten to (until=<<((==)=<<))f. Using the $ operator to get rid of the outer parentheses and substituting f with sum.primeFactors yields the solution from above.

\$\endgroup\$
  • 4
    \$\begingroup\$ =<<((==)=<<)$ Whaaaaaat. \$\endgroup\$ – totallyhuman Oct 5 '17 at 4:52
  • 2
    \$\begingroup\$ @icrieverytim I added an explanation. Feel free to ask in the Haskell chat room if you have further questions on how this sorcery works. \$\endgroup\$ – Laikoni Oct 5 '17 at 8:14
5
\$\begingroup\$

Husk, 4 bytes

ω(Σp

Try it online!

Explanation:

ω(   -- apply the following function until the result no longer changes (fixpoint)
  Σ  -- sum
   p -- the list of primefactors
\$\endgroup\$
4
\$\begingroup\$

Pyth, 3 bytes

usP

Try it here.

Explanation:

usPGQ The trailing GQ is implicit
  PG  Get prime factors
 s    Sum
u   Q Repeat until returned value no longer unique starting with the input
\$\endgroup\$
  • \$\begingroup\$ Did you forget to update your explanation? \$\endgroup\$ – MCMastery Oct 6 '17 at 1:56
  • 1
    \$\begingroup\$ @MCMastery No, the code and the explanation are the same. The trailing GQ is implicit \$\endgroup\$ – totallyhuman Oct 6 '17 at 6:35
  • \$\begingroup\$ @MCMastery what i cri everytim said \$\endgroup\$ – Erik the Outgolfer Oct 6 '17 at 11:21
4
\$\begingroup\$

Python 2, 84 bytes

f=lambda n,d=2:n>1and(n%d and f(n,d+1)or d+f(n/d))
i=input()
exec'i=f(i);'*i
print i

Try it online!

\$\endgroup\$
  • \$\begingroup\$ This may be a pretty dumb question, but how does f=lambda n,d=2:n>1and(n%d and f(n,d+1)or d+f(n/d)) work? I've never programmed in Python (mainly Java and C#), so I'm unsure what the result of this function is. Does this function modify the input n and return it afterwards, or is it similar to a boolean where n>1and(n%d and f(n,d+1)or d+f(n/d)) is either 0 or 1, or 0 or n, or something else? I'm trying to visualize how a port of this would look like in Java/C#, but I'm unable to because I don't really understand Python lambdas like this in general. \$\endgroup\$ – Kevin Cruijssen Oct 4 '17 at 14:41
  • 1
    \$\begingroup\$ @KevinCruijssen this is equivalent to n>1 ? (n%d!=0 ? f(n, d+1) : d+f(n/d)) : n>1. In general terms x and y is equivalent to x ? y : x. x and y or z is equivalent to x ? y : z in most cases. \$\endgroup\$ – ovs Oct 4 '17 at 15:06
  • 1
    \$\begingroup\$ @KevinCruijssen a Java port would be something like f=(n,d=2)->n>1?n%d>0?f(n,d+1):d+f(n/d):0. \$\endgroup\$ – ovs Oct 4 '17 at 15:08
  • \$\begingroup\$ Ah ok. Thanks for the explanation, now it makes a lot more sense. And I remember x and y being x ? y : x from JavaScript as well. Thanks! \$\endgroup\$ – Kevin Cruijssen Oct 4 '17 at 17:30
4
\$\begingroup\$

Java 8, 175 144 142 141 bytes

n->{for(int i,t=n,x;;n=t){for(i=2;i<t;t=t%i++<1?0:t);if(t>1|n<5)return n;for(t=0,i=1;i++<n;)for(;n%i<1;n/=i,t+=x)for(x=i;x>9;x/=10)t+=x%10;}}

-1 byte thanks to @Nevay.

Unlike single bytes in some of the golfing languages, Java is pretty verbose for prime-checks, prime-factors, digit-sums, and such, so I guess less than 200 isn't too shabby.
Can most likely still be golfed by combining loops and not using a separated recursive method for the digit sum.

Explanation:

Try it here.

n->{                // Method with integer as both parameter and return-type
  for(int i,        //  Index-integer `i`
          t=n,      //  Temp integer `t`, starting at the input `n`
          x;        //  Temp integer `x`
      ;             //  Loop (1) indefinitely
      n=t){         //    After every iteration, replace `n` with the value `t`
    for(i=2;        //   Reset `i` to 2
        i<t;        //   Inner loop (2) from 2 to `t` (exclusive)
        t=t%i++<1?  //    If `t` is divisible by `i`:
           0        //     Set `t` to 0
          :         //    Else:
           t        //     Leave `t` the same
    );              //   End of inner loop (2)
    if(t>1          //   If `t` is not 0 (it means it's a prime),
       |n<5)        //   or if `n` is below 5 (for edge-cases `4` and 'prime' `1`)
      return n;     //    Return `n` as result
    for(t=0,        //   Reset `t` to 0
        i=1;        //   Reset `i` to 1
        i++<n;)     //   Inner loop (3) from 2 to `n` (inclusive)
      for(;n%i<1;   //    Inner loop (4) as long as `n` is divisible by `i`
          n/=i,     //      After every iteration: Divide `n` by `i`,
          t+=x)     //      and increase `t` by `x`
        for(x=i;    //     Reset `x` to `i`
            x>9;    //     Inner loop (5) as long as `x` contains more than 1 digit
            x/=10)  //       After every iteration, remove the trailing digit
          t+=n%10;  //      Increase `t` with the trailing digit of `n`
                    //     End of inner loop (5) (implicit / single-line body)
                    //    End of inner loop (4) (implicit / single-line body)
                    //   End of inner loop (3) (implicit / single-line body)
  }                 //  End of loop (1)
}                   // End of method
\$\endgroup\$
  • 6
    \$\begingroup\$ +1 for bothering to write an explanation as verbose as if this was a golfing language. \$\endgroup\$ – someone Oct 4 '17 at 12:17
  • \$\begingroup\$ @someone Thanks! Since someone asked me about an explanation of a Java answer of mine once in the past, I've been adding them to all my answers. :) \$\endgroup\$ – Kevin Cruijssen Oct 4 '17 at 12:23
  • \$\begingroup\$ i,t=n,x looks like it belongs in Python, haha \$\endgroup\$ – ETHproductions Oct 4 '17 at 14:03
  • \$\begingroup\$ @ETHproductions Hehe, too bad I still have to add the leading int (unlike Python). ;) \$\endgroup\$ – Kevin Cruijssen Oct 4 '17 at 14:15
  • \$\begingroup\$ You can use i++<n instead of ++i<=n. \$\endgroup\$ – Nevay Oct 4 '17 at 21:47
3
\$\begingroup\$

Jelly, 5 bytes

ÆfS$¡

Explanations:

Æf    list of prime factors
  S   sum
   $¡ repeat n times

Try it online!

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

Retina, 30 bytes

{+`(\1|\b11+?\B)+$
$1;$#1$*
;

Input and output in unary.

Try it online! (Performs decimal/unary conversion for convenience.)

Explanation

{+`(\1|\b11+?\B)+$
$1;$#1$*

The { instructs Retina to run the entire program in a loop until a full pass fails to modify the string, i.e. until a fixed point is reached. Consequently, the program itself computes one step of summing the prime factors of the current value.

This stage itself computes the prime factorisation of the input. The + is similar to { but loops only this stage until it stops changing the string. The regex tries to match the final run of 1s by repeatedly matching the same substring (i.e. the factor). The way this is done is a bit convoluted due to the forward reference \1. On the first iteration, group 1 hasn't captured anything yet, so \1 fails unconditionally. Instead, we have to match \b11+?\B which is the smallest possible substring that starts at the beginning of the run, contains at least two 1s and doesn't cover the entire run. Subsequent iterations will not be able to use this alternative again, due to the \b. So on all further iterations, we're matching \1, i.e. the same substring over and over again. This process has to hit the end of the string exactly ($) to make sure we've captured and actual divisor. The benefit of using this somewhat tricky approach is that group 1 will have been used exactly n/d times, i.e. what remains after dividing out the divisor d.

We replace this match with d ($1), a separating ; and n/d ($#1$*, which inserts $#1 copies of 1, where $#1 is the number of captures made by group 1).

This process stops once the final run in the string is itself a prime, because then the regex no longer matches.

;

All we need to do to sum the primes is to remove all the separators.

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

Ohm v2, 4 bytes

·ΘoΣ

Try it online!

Explanation:

·Θ    evaluate the block until the result returned has already been seen
   Σ  sum
  o   the full prime factorization
\$\endgroup\$
2
\$\begingroup\$

Actually, 7 bytes

⌠w♂πΣ⌡Y

Try it online!

Explanation:

⌠w♂πΣ⌡Y
⌠    ⌡Y  do this until output stops changing (fixed-point combinator)
 w         factor into [prime, exponent] pairs
  ♂π       product of each pair
    Σ      sum of products
\$\endgroup\$
2
\$\begingroup\$

R + pracma, 53 bytes

function(n){for(i in 1:n)n=sum(pracma::factors(n))
n}

Try it online! (r-fiddle)

R doesn't have a prime factors builtin, but numerous packages (pracma, numbers, etc.) do, so I picked a conveniently short one.

\$\endgroup\$
1
\$\begingroup\$

Jelly, 6 bytes

This answer uses one of Jelly's many prime factorization builtins, and the quick for repeat until the results are no longer unique.

ÆfSµÐL

Try it online!

\$\endgroup\$
  • \$\begingroup\$ I think you've been outgolfed but, given your approach, I'm uncertain whether that answer works \$\endgroup\$ – caird coinheringaahing Oct 4 '17 at 11:10
  • \$\begingroup\$ @cairdcoinheringaahing I've just checked his answer (or rather, the Python equivalent) from 1 to 100000 and it works. I think 1 is the only case where the number of steps needed is equal to n (which is fine; with 1 we only need to run it once), and there don't seem to be any cases where the number of steps is greater than n (i.e. there don't seem to be any counterexamples). Ah well, I've been outgolfed :D \$\endgroup\$ – Sherlock9 Oct 4 '17 at 11:25
  • \$\begingroup\$ Well, it happens. Although +1 for being the exact same code I thought of when I saw this challenge \$\endgroup\$ – caird coinheringaahing Oct 4 '17 at 11:27
  • \$\begingroup\$ The sum of prime factors of n is always less than or equal to n, which makes it pretty easy to prove that n is always more than enough. \$\endgroup\$ – Chris Oct 5 '17 at 1:37
1
\$\begingroup\$

MATL, 6 bytes

Uses scottinet's idea of looping more times than needed. Thanks also to Shaggy for a pointing out a mistake, now corrected.

t:"Yfs

Try it online!

Explanation

t       % Take input (implicit). Duplicate
:"      % Do the following that many times
  Yf    %   Array of prime factors
  s     %   Sum of array
        % End (implicit). Display (implicit)
\$\endgroup\$
  • \$\begingroup\$ This seems to fail for 4. \$\endgroup\$ – Shaggy Oct 4 '17 at 11:11
  • \$\begingroup\$ @Shaggy Thanks! Working on that \$\endgroup\$ – Luis Mendo Oct 4 '17 at 11:11
  • \$\begingroup\$ @Shaggy Solved now \$\endgroup\$ – Luis Mendo Oct 4 '17 at 11:16
1
\$\begingroup\$

PowerShell, 124 bytes

function f($a){for($i=2;$a-gt1){if(!($a%$i)){$i;$a/=$i}else{$i++}}}
for($x=$args[0];$l-ne$x){$l=$x;$x=(f($x))-join'+'|iex}$x

Try it online!

PowerShell doesn't have any prime factorization built-ins, so this uses code from my answer on Prime Factors Buddies (the top line) to perform the factorization calculations.

The second line is the meat of this program. We take input from $args into $x, then for loop until $l is -notequal to $x. (The first iteration, $l is $null and $x is an integer, so we'll loop at least once).

Inside the loop, we set our $l = $x to determine if we've hit the end of the loop or not. Then we get the factors of $x with f($x), -join those together with + and |iex them (short for Invoke-Expression and similar to eval). That's stored back into $x. Thus, we've hit the "end" where the prime factorization summed together is back to itself. Then, we simply place $x on the pipeline and output is implicit.

\$\endgroup\$
0
\$\begingroup\$

Mathematica, 35 bytes

#//.x_:>Tr[1##&@@@FactorInteger@x]&

Try it online!

(Mathics does not support Tr. I have to implement it manually)

\$\endgroup\$
  • 4
    \$\begingroup\$ 1##& is short for Times and FixedPoint can almost always be shortened with //.: #//.x_:>Tr[1##&@@@FactorInteger@x]& \$\endgroup\$ – Martin Ender Oct 4 '17 at 10:53
  • \$\begingroup\$ @MartinEnder Thanks! I should have already known about Times, but I've not known about the FixedPoint trick. \$\endgroup\$ – user202729 Oct 4 '17 at 11:06
  • \$\begingroup\$ Your code is written in Mathematica. This is not a Mathics function. You should either change the language name to Mathematica or Tr to Total \$\endgroup\$ – J42161217 Oct 4 '17 at 11:36
  • \$\begingroup\$ @{no one} Sorry, language name (Mathics) was a mistake. {i cri evritime} fixed that. \$\endgroup\$ – user202729 Oct 4 '17 at 12:28
  • \$\begingroup\$ FYI, I opened a PR to add Tr to Mathics a while back. \$\endgroup\$ – Mego Oct 4 '17 at 13:56
0
\$\begingroup\$

Ruby, 63 bytes

->n{n.times{n=n.prime_division.map{|x|x.reduce:*}.sum};n}

Try it online!

Uses the -rprime flag for +6 bytes to make use of Prime#prime_division.

prime_division returns pairs of [prime, exponent] (for example, for 24 we have the factors [2, 2, 2, 3] so it gives [[2, 3], [3, 1]]) so in each step we just multiply the members of those pairs together and sum the results.

\$\endgroup\$
0
\$\begingroup\$

Javascript (ES6), 63 bytes

f=n=>(q=(p=(m,x)=>m<x?0:m%x?p(m,x+1):x+p(m/x,x))(n,2))^n?f(q):q
<input id=i type=number min=0 value=0 oninput="o.innerText=f(i.value)">
<p id=o></p>

Ungolfed:

f=n=>(                  // Recursive function `f`
    p=(m,x=2)=>(        //   Recursive function `p`, used to sum prime factors
        m<x?            //     If m (the number to be factored) is less than x (the current
            0           //     iteration), return 0
        :m%x?           //     Else if m doesn't divide x
            p(m,x+1)    //     run the next iteration
        :               //     Else (if m divides x)
            x+p(m/x,x)  //     Divide m by x and repeat the current iteration
    ),
    q=p(n),             //   Set q to the sum of the prime factors of n
    q^n?                //   If q != n then
        f(q)            //     repeat f with q
    :                   //   else
        q               //     return q
)
\$\endgroup\$
0
\$\begingroup\$

Java 8, 101 bytes

n->{for(int i=n;i-->0;n=f(n,2));return n;}int f(int n,int d){return n>1?n%d>0?f(n,d+1):d+f(n/d,2):0;}

Port of @ovs's amazing Python 2 answer.

Explanation:

Try it here.

n->{                  // Method with integer as both parameter and return-type
  for(int i=n;i-->0;  //  Loop the input amount of times
    n=f(n,2)          //   And change `n` that many times with a separate method call
  );                  //  End of loop
  return n;           //  Then return the integer `n` as result
}                     // End of method

int f(int n,int d){   // Separated method with 2 integer parameters and integer return-type
                      // (`d` is 2 when we initially call this recursive-method)
  return n>1?         //  If input `n` is larger than 1:
    n%d>0?            //   And it's not divisible by `d`:
     f(n,d+1)         //    Do a recursive-call with `n, d+1`
    :                 //   Else:
     d                //    Sum `d` with
      +f(n/d,2)       //    a recursive call with `n/d, 2`
   :                  //  Else:
    0;                //   Simply return 0
}                     // End of separated method
\$\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.