29
\$\begingroup\$

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 \$\text{UR}(\cdot)\$ to denote the ultraradical function. For example, \$\text{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.

\$\endgroup\$

22 Answers 22

12
\$\begingroup\$

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)

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

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 .

\$\endgroup\$
8
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ Would a linear search take less bytes? \$\endgroup\$ Commented Sep 23, 2019 at 2:57
8
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ 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). \$\endgroup\$ Commented Sep 23, 2019 at 17:52
  • 1
    \$\begingroup\$ @Joel I've added a safer version. \$\endgroup\$ Commented Sep 23, 2019 at 18:25
6
\$\begingroup\$

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\$.

\$\endgroup\$
2
  • \$\begingroup\$ This is very cool. Sadly J does not seem able to perform this inversion \$\endgroup\$ Commented Sep 23, 2019 at 12:04
  • \$\begingroup\$ @dzaima Why didn't I see that‽ Thank you. \$\endgroup\$ Commented Sep 24, 2019 at 11:31
5
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ @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.) \$\endgroup\$ Commented Sep 23, 2019 at 15:42
4
\$\begingroup\$

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.

\$\endgroup\$
4
  • 2
    \$\begingroup\$ 43 bytes \$\endgroup\$ Commented Sep 23, 2019 at 10:14
  • \$\begingroup\$ @RobinRyder that’s sufficiently different that I think you should post your own answer. Thanks though! \$\endgroup\$ Commented Sep 23, 2019 at 10:36
  • 1
    \$\begingroup\$ OK, thanks. Here it is. \$\endgroup\$ Commented Sep 23, 2019 at 11:49
  • \$\begingroup\$ "Unfortunately", polyroot returns all complex roots ... Otherwise it would win. \$\endgroup\$ Commented Sep 25, 2019 at 15:17
3
\$\begingroup\$

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 {:

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

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

\$\endgroup\$
2
\$\begingroup\$

Pari/GP, 34 32 26 24 bytes

a->-solve(X=0,a,a-X-X^5) 

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ 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. :) \$\endgroup\$ Commented Sep 23, 2019 at 11:31
  • \$\begingroup\$ Thanks for the tip @KevinCruijssen. The issue is actually for the whole of \$\Bbb R^-\$, but please see the workaround :) \$\endgroup\$ Commented Sep 23, 2019 at 12:06
  • \$\begingroup\$ You can use an anonymous function: a->solve(X=-a,a,X^5+X+a). \$\endgroup\$ Commented Sep 23, 2019 at 12:46
  • \$\begingroup\$ Thanks @alephalpha. \$\endgroup\$ Commented Sep 23, 2019 at 13:03
2
\$\begingroup\$

05AB1E, 12 bytes

ΔyIy4m>/+5/- 

Try it online!

Newton's method.

\$\endgroup\$
2
\$\begingroup\$

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} 
\$\endgroup\$
3
  • \$\begingroup\$ @ngn lol, that was careless... updated but now in k4 as i'm too lazy to do it in ngn/k or oK :) \$\endgroup\$ Commented Oct 9, 2019 at 19:44
  • \$\begingroup\$ cool! the last pair of [ ] seems unnecessary \$\endgroup\$ Commented Oct 9, 2019 at 19:49
  • \$\begingroup\$ 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! \$\endgroup\$ Commented Oct 9, 2019 at 20:05
1
\$\begingroup\$

Pari/GP, 24 bytes

a->polrootsreal(x^5+x+a) 

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Nice, didn't know that solve has an analogue \$\endgroup\$ Commented Sep 23, 2019 at 13:20
1
\$\begingroup\$

Octave, 25 bytes

@(a)fzero(@(x)x^5+x+a,-a) 

Try it online!

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

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.

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

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.

\$\endgroup\$
2
  • \$\begingroup\$ Would something like x-=t=... work? \$\endgroup\$ Commented Sep 25, 2019 at 2:15
  • 1
    \$\begingroup\$ 82 bytes \$\endgroup\$ Commented Sep 28, 2019 at 1:52
1
\$\begingroup\$

MMIX, 68 bytes (17 instrs)

(jelly-style xxd -g4)

00000000: e0043ff0 e0034014 79010001 3b01013f ṭ¥?ṅṭ¤@Þy¢¡¢;¢¢? 00000010: e8013ff0 c1020100 10ff0202 10ffffff ċ¢?ṅḊ£¢¡Ñ”££Ñ””” 00000020: 1001ff02 10ffff03 e4010020 04ffff04 Ñ¢”£Ñ””¤ỵ¢¡ ¥””¥ 00000030: 06010100 140101ff 11020102 5b02fff6 ©¢¢¡Þ¢¢”×£¢£[£”ẇ 00000040: f8020000 ẏ£¡¡ 

Disassembly

bringr SETH $4,#3FF0 // one = 1. SETH $3,#4014 // five = 5. ZSNN $1,$0,1 // x = (a neg? 0 : 1) SLU $1,$1,63 // x <<= 63 ORH $1,#3FF0 // x |= 1. [now x = a neg? 1. : -1.] 0H SET $2,$1 // loop: px = x FMUL $255,$2,$2 // t = px *. px FMUL $255,$255,$255 // t = t *. t FMUL $1,$255,$2 // x = t *. px FMUL $255,$255,$3 // px = px *. five INCH $1,#20 // x *.= 4. (bit trick: add two to exponent) FADD $255,$255,$4 // t = t +. one FSUB $1,$1,$0 // x = x -. a FDIV $1,$1,$255 // x = x /. t FCMPE $2,$1,$2 // px = epsilon_comp(x, px) PBNZ $2,0B // iflikely(px) goto loop POP 2,0 // return x 

I used WolframAlpha to simplify Newton's method for this. It said that \$\def\d{{\rm d}}x-{x^5+x+a\over{\d\over \d x}x^5+x+a}\$ simplified down to \$4x^5-a\over5x^4+1\$. The convergence test here is a builtin epsilon-convergence, so rE must be set by the calling function.

For faster convergence, change ORH $1,#3FF0 to

 SLU $255,$0,1 // 3BFF0001 ;”¡¢ shift left to erase sign INCH $255,#8020 // E4FF8020 ỵ”⁰ unbias exponent PUT rD,0 // F7010000 ẋ¢¡¡ prep dividend DIVU $2,$255,5 // 1F02FF05 þ£”¦ take approximate fifth root CSN $2,$255,$255 // 6002FFFF `£”” and use that if we are >1 INCH $2,#7FE0 // E4027FE0 ỵ£¶ṭ rebias exponent SRU $255,$2,1 // 3FFF0201 ?”£¢ shift right again OR $1,$1,$255 // C00101FF Ċ¢¢” or sign and guess 
\$\endgroup\$
1
\$\begingroup\$

Excel (Insider Beta), 59 bytes

=h(a1,1) h =LAMBDA(a,x,IF(a=x^5+x,x,h(a,(a/(x^5+x))^0.2*x))) in name manager 

1 byte for name h in name manager, 49 bytes for formula for h, 9 bytes for calling h. Uses successive approximations using the 5th root of a/(x^0.5+x) times x. Initial call uses 1 for x.

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

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%.

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

Python 3 + sympy, 72 bytes

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

Try it online!

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

TI-Basic (TI-83), 12 bytes

solve(X^5+X+Ans,X,0 

TI-Basic (TI-89), 13* bytes

solve(x^5+x=-a,x)→f(a) 

*Not completely sure how to score ti-89 programs/functions

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

Scala, 74 bytes

Using Newton-Raphson with a fixed number of iterations, and the same approximation trick as @Arnauld

Golfed version. Try it online!

def f(a:Double)={var x=a/5;(1 to 99).foreach{_=>x-=(a/(x*x*x*x+1)+x)/5};x} 

Ungolfed version. Try it online!

import scala.math._ object Main { def main(args: Array[String]): Unit = { val f: Double => Double = a => { var x = a / 5 (1 to 99).foreach { _ => x -= (a / (x * x * x * x + 1) + x) / 5 } x } val inputs = List(-100010.0, 0.0, 1.0, -1.0, exp(1), pow(2, 0.5), 1073741888.0) inputs.foreach { x => println(s"%.9f --> %.9f".format(x, f(x))) } } } 
\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.