# Calculate the Ultraradical

## What is the Ultraradical

The ultraradical, or the Bring radical, of a real number $$\a\$$ is defined as the only real root of the quintic equation $$\x^5+x+a=0\$$.

Here we use $$\UR(\cdot)\$$ to denote the ultraradical function. For example, $$\UR(-100010)=10\$$, since $$\10^5+10-100010=0\$$.

## Challenge

Write a full program or a function, that takes a real number as input, and returns or outputs its ultraradical.

## Requirements

No standard loopholes are allowed. The results for the test cases below must be accurate to at least 6 significant digits, but in general the program should calculate the corresponding values for any valid real number inputs.

## Test Cases

9 decimal places rounded towards 0 are given for reference. Explanation is added for some of the test cases.

 a                         | UR(a)
---------------------------+---------------------
0             |   0.000 000 000        # 0
1             |  -0.754 877 (666)      # UR(a) < 0 when a > 0
-1             |   0.754 877 (666)      # UR(a) > 0 when a < 0
1.414 213 562 |  -0.881 616 (566)      # UR(sqrt(2))
-2.718 281 828 |   1.100 93(2 665)      # UR(-e)
3.141 592 653 |  -1.147 96(5 385)      # UR(pi)
-9.515 716 566 |   1.515 71(6 566)      # 5th root of 8, fractional parts should match
10             |  -1.533 01(2 798)
-100             |   2.499 20(3 570)
1 000             |  -3.977 89(9 393)
-100 010             |  10.000 0(00 000)      # a = (-10)^5 + (-10)
1 073 741 888             | -64.000 0(00 000)      # a = 64^5 + 64


## Winning Criteria

The shortest valid submission in every language wins.

# Wolfram Language (Mathematica), 20 bytes

Root[xx^5+x+#,1]&


Try it online!

Still a built-in, but at least it isn't UltraRadical.

(the character  is displayed like |-> in Mathematica, similar to => in JS)

• I keep wondering why Mathematica uses  and  instead of ↦ and ᵀ – Adám Sep 23 '19 at 12:19
• @Adám am I supposed to just see squares for the first two, or am I missing some kind of font... – mbrig Sep 24 '19 at 17:11
• @mbrig Just squares. That's my point. Mathematica uses characters in the Private Use Areas even though Unicode does have most of them. – Adám Sep 24 '19 at 17:39

# Python 3.8 (pre-release), 60 bytes

f=lambda n,x=0:x!=(a:=x-(x**5+x+n)/(5*x**4+1))and f(n,a)or a


Try it online!

Newton iteration method. $$\ x' = x - \frac {f(x)} {f'(x)} = x - \frac {x^5+x+n} {5x^4+1}\$$

While using $$\ \frac {4x^5-n} {5x^4+1} \$$ is mathematically equivalent, it makes the program loop forever.

Other approach:

# Python 3.8 (pre-release), 102 bytes

lambda x:a(x,-x*x-1,x*x+1)
a=lambda x,l,r:r<l+1e-9and l or(m:=(l+r)/2)**5+m+x>0and a(x,l,m)or a(x,m,r)


Try it online!

Binary search, given that the function x^5+x+a is increasing. Set the bounds to -abs(x) and abs(x) is enough but -x*x-1 and x*x+1 is shorter.

BTW Python's recursion limit is a bit too low so it's necessary to have 1e-9, and the := is called the walrus operator.

• Would a linear search take less bytes? – user202729 Sep 23 '19 at 2:57

# JavaScript (ES7), 44 bytes

A safer version using the same formula as below but with a fixed number of iterations.

n=>(i=1e3,g=x=>i--?g(.8*x-n/(5*x**4+5)):x)


Try it online!

# JavaScript (ES7),  43  42 bytes

Newton's method, using $$\5x^4+5\$$ as an approximation of $$\f'(x)=5x^4+1\$$.

n=>(g=x=>x-(x-=(x+n/(x**4+1))/5)?g(x):x)


Try it online!

### How?

We start with $$\x_0=0\$$ and recursively compute:

$$x_{k+1}=x_k-\frac{{x_k}^5+x_k+n}{5{x_k}^4+5}=x_k-\frac{x_k+\frac{n}{{x_k}^4+1}}{5}$$

until $$\x_k-x_{k+1}\$$ is insignificant.

• Since comparing equivalence of floating numbers is inaccurate, I am not sure whether the termination of the program can be guaranteed for every possible input (the Python 3 answer below already experienced issues when attempting to shorten the formula). – Joel Sep 23 '19 at 17:52
• @Joel I've added a safer version. – Arnauld Sep 23 '19 at 18:25

# Jelly, 8 bytes

;17B¤ÆrḢ


Try it online!

How it works:

• Constructs the list [a, 1, 0, 0, 0, 1] by prepending a to the binary representation of 17. Why this list? Because it corresponds to the coefficients we are looking for:

[a, 1, 0, 0, 0, 1] -> P(x) := a + 1*x^1 + 0*x^2 + 0*x^3 + 0*x^4 + 1*x^5 = a + x + x^5

• Then, Ær is a built-in that solves the polynomial equation P(x) = 0, given a list of coefficients (what we constructed earlier).

• We are only interested in the real solution, so we take the first entry in the list of solutions with Ḣ.

# APL (Dyalog Unicode), 11 10 bytesSBCS

-1 thanks to dzaima

Anonymous tacit prefix function.

(--*∘5)⍣¯1


Try it online!

()⍣¯1 apply the following tacit function negative one time:

- the negated argument

- minus

*∘5 the argument raised to the power of 5

In essence, this asks: Which $$\x\$$ do I need to feed to $$\f(x)=-x-x^5\$$ such that the result becomes $$\y\$$.

• This is very cool. Sadly J does not seem able to perform this inversion – Jonah Sep 23 '19 at 12:04
• @dzaima Why didn't I see that‽ Thank you. – Adám Sep 24 '19 at 11:31

# R, 43 bytes

function(a)nlm(function(x)abs(x^5+x+a),a)$e  Try it online! nlm is an optimization function, so this searches for the minimum of the function $$\x\mapsto |x^5+x+a|\$$, i.e. the only zero. The second parameter of nlm is the initialization point. Interestingly, initializing at 0 fails for the last test case (presumably because of numerical precision), but initializing at a (which isn't even the right sign) succeeds. • @TheSimpliFire Mathematically, it is equivalent, but numerically, it isn't: using the square instead of the absolute value leads to the wrong value for large input. (Try it online.) – Robin Ryder Sep 23 '19 at 15:42 # R, 56 bytes function(x)(y=polyroot(c(x,1,0,0,0,1)))[abs(Im(y))<1e-9]  Try it online! Thanks to @Roland for pointing out polyroot. I have also realised my previous answer picked a complex root for zero or negative $$\a\$$ so now rewritten using polyroot and filtering complex roots. • 43 bytes – Robin Ryder Sep 23 '19 at 10:14 • @RobinRyder that’s sufficiently different that I think you should post your own answer. Thanks though! – Nick Kennedy Sep 23 '19 at 10:36 • OK, thanks. Here it is. – Robin Ryder Sep 23 '19 at 11:49 • "Unfortunately", polyroot returns all complex roots ... Otherwise it would win. – Roland Sep 25 '19 at 15:17 # J, 14 bytes {:@;@p.@,#:@17  Try it online! J has a built in for solving polynomials... p. The final 4 test cases timeout on TIO, but in theory are still correct. ## how The polynomial coefficients for J's builtin are taken as a numeric list, with the coefficient for x^0 first. This means the list is: a 1 0 0 0 1  1 0 0 0 1 is 17 in binary, so we represent it as #:@17, then append the input ,, then apply p., then unbox the results with raze ;, then take the last element {: # Ruby, 53 41 bytes ->a{x=a/=5;99.times{x-=a/(x**4+1)+x/5};x}  Try it online! Using Newton-Raphson with a fixed number of iterations, and the same approximation trick as Arnauld # Pari/GP, 343226 24 bytes a->-solve(X=0,a,a-X-X^5)  Try it online! • Nice answer, but out of curiosity: why does s(-100010) result in -8.090... - 5.877...*I instead of just 10? Is this a limitation of the language for large test cases? PS: You can save 2 bytes changing both 0.2 to .2. :) – Kevin Cruijssen Sep 23 '19 at 11:31 • Thanks for the tip @KevinCruijssen. The issue is actually for the whole of $\Bbb R^-$, but please see the workaround :) – TheSimpliFire Sep 23 '19 at 12:06 • You can use an anonymous function: a->solve(X=-a,a,X^5+X+a). – alephalpha Sep 23 '19 at 12:46 • Thanks @alephalpha. – TheSimpliFire Sep 23 '19 at 13:03 # 05AB1E, 12 bytes ΔyIy4m>/+5/-  Try it online! Newton's method. # k4, 33 31 bytes {{y-(x+y+*/5#y)%5+5*/4#y}[x]/x}  newton-raphson computed iteratively until a number is converged on edit: -2 thanks to ngn! whoops, got this all wrong... # K (oK), 10 bytes {-x+*/5#x}  • @ngn lol, that was careless... updated but now in k4 as i'm too lazy to do it in ngn/k or oK :) – scrawl Oct 9 '19 at 19:44 • cool! the last pair of [ ] seems unnecessary – ngn Oct 9 '19 at 19:49 • hmm, you're right. i've encountered strange behaviour before where over/converge results in an infinite loop because of extraneous/omitted (one or the other, i forget) brackets. that's why i left them in but i should have checked. thanks! – scrawl Oct 9 '19 at 20:05 # Pari/GP, 24 bytes a->polrootsreal(x^5+x+a)  Try it online! • Nice, didn't know that solve has an analogue – TheSimpliFire Sep 23 '19 at 13:20 # Octave, 25 bytes @(a)fzero(@(x)x^5+x+a,-a)  Try it online! # Maplesoft Maple, 23 bytes f:=a->fsolve(x^5+x+a=0)  Unfortunately, there is no online Maple compiler/calculator out there AFAIK. But the code is pretty straightforward. C,118b/96b #include<math.h> double ur(double a){double x=a,t=1;while(fabs(t)>1e-6){t=x*x*x*x;t=(x*t+x+a)/(5*t+1);x-=t;}return x;}  118 bytes with original function name and with some extra accuracy (double). With bit hacks may be better, but unportable. 96 bytes with fixed iterations. double ur(double a){double x=a,t;for(int k=0;k<99;k++){t=x*x*x*x;x=(4*x*t-a)/(5*t+1);}return x;}  Actually, our function is so good we can use better adaptations of Newton's method. Much faster and practical implementation (150 bytes) would be #include<math.h> double ur(double a){double x=a/5,f=1,t;while(fabs(f)>1e-6){t=x*x*x*x;f=(t*(5*t*x+5*a+6*x)+a+x)/(15*t*t-10*a*x*x*x+1);x-=f;}return x;}  I checked it works, but I'm too lazy to find out how much more fast it would be. Should be at least one more order faster as Newton's. • Would something like x-=t=... work? – user202729 Sep 25 '19 at 2:15 • 82 bytes – ceilingcat Sep 28 '19 at 1:52 # Clean, 61 60 bytes import StdEnv$a=iter 99(\x=(3.0*x^5.0-a)/inc(4.0*x^4.0))0.0


Try it online!

Newton's method, first implemented in user202729's answer.

# Clean, 124 bytes

import StdEnv
\$a= ?a(~a)with@x=abs(x^5.0+x+a);?u v|u-d==u=u|v+d==v=v= ?(u+if(@u< @v)0.0d)(v-if(@u> @v)0.0d)where d=(v-u)/3E1


Try it online!

A "binary" search, narrowing the search area to the upper or lower 99.6% of the range between the high and low bounds at each iteration instead of 50%.

# Python 3 + sympy, 72 bytes

lambda y:float(sympy.poly("x**5+x+"+str(y)).all_roots()[0])
import sympy


Try it online!