Calculate the Ultraradical

25

1

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.

Shieru Asakoto

Posted 2019-09-23T01:46:54.880

Reputation: 4 445

Answers

12

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)

user202729

Posted 2019-09-23T01:46:54.880

Reputation: 14 620

9I keep wondering why Mathematica uses and instead of and – Adám – 2019-09-23T12:19:42.107

2@Adám am I supposed to just see squares for the first two, or am I missing some kind of font... – mbrig – 2019-09-24T17:11:15.113

6

@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 – 2019-09-24T17:39:04.430

8

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.

user202729

Posted 2019-09-23T01:46:54.880

Reputation: 14 620

Would a linear search take less bytes? – user202729 – 2019-09-23T02:57:08.253

8

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.

Arnauld

Posted 2019-09-23T01:46:54.880

Reputation: 111 334

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 – 2019-09-23T17:52:09.457

1@Joel I've added a safer version. – Arnauld – 2019-09-23T18:25:20.453

7

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 .

Mr. Xcoder

Posted 2019-09-23T01:46:54.880

Reputation: 39 774

6

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

Adám

Posted 2019-09-23T01:46:54.880

Reputation: 37 779

This is very cool. Sadly J does not seem able to perform this inversion – Jonah – 2019-09-23T12:04:14.130

@dzaima Why didn't I see that‽ Thank you. – Adám – 2019-09-24T11:31:58.560

5

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.

Robin Ryder

Posted 2019-09-23T01:46:54.880

Reputation: 6 625

@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 – 2019-09-23T15:42:41.407

4

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.

Nick Kennedy

Posted 2019-09-23T01:46:54.880

Reputation: 11 829

243 bytes – Robin Ryder – 2019-09-23T10:14:29.607

@RobinRyder that’s sufficiently different that I think you should post your own answer. Thanks though! – Nick Kennedy – 2019-09-23T10:36:11.530

1

OK, thanks. Here it is.

– Robin Ryder – 2019-09-23T11:49:58.000

"Unfortunately", polyroot returns all complex roots ... Otherwise it would win. – Roland – 2019-09-25T15:17:32.747

3

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

Jonah

Posted 2019-09-23T01:46:54.880

Reputation: 8 729

3

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

G B

Posted 2019-09-23T01:46:54.880

Reputation: 11 099

2

Pari/GP, 34 32 26 24 bytes

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

Try it online!

TheSimpliFire

Posted 2019-09-23T01:46:54.880

Reputation: 237

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 – 2019-09-23T11:31:16.990

Thanks for the tip @KevinCruijssen. The issue is actually for the whole of $\Bbb R^-$, but please see the workaround :) – TheSimpliFire – 2019-09-23T12:06:47.037

You can use an anonymous function: a->solve(X=-a,a,X^5+X+a). – alephalpha – 2019-09-23T12:46:24.797

Thanks @alephalpha. – TheSimpliFire – 2019-09-23T13:03:00.930

2

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}

scrawl

Posted 2019-09-23T01:46:54.880

Reputation: 1 079

@ngn lol, that was careless... updated but now in k4 as i'm too lazy to do it in ngn/k or oK :) – scrawl – 2019-10-09T19:44:59.767

cool! the last pair of [ ] seems unnecessary – ngn – 2019-10-09T19:49:32.840

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 – 2019-10-09T20:05:03.800

2

05AB1E, 12 bytes

ΔyIy4m>/+5/-

Try it online!

Newton's method.

Grimmy

Posted 2019-09-23T01:46:54.880

Reputation: 12 521

1

Pari/GP, 24 bytes

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

Try it online!

alephalpha

Posted 2019-09-23T01:46:54.880

Reputation: 23 988

Nice, didn't know that solve has an analogue – TheSimpliFire – 2019-09-23T13:20:01.193

1

Octave, 25 bytes

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

Try it online!

tsh

Posted 2019-09-23T01:46:54.880

Reputation: 13 072

1

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.

polfosol ఠ_ఠ

Posted 2019-09-23T01:46:54.880

Reputation: 519

1

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.

sanaris

Posted 2019-09-23T01:46:54.880

Reputation: 159

Would something like x-=t=... work? – user202729 – 2019-09-25T02:15:00.617

182 bytes – ceilingcat – 2019-09-28T01:52:06.750

0

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

Οurous

Posted 2019-09-23T01:46:54.880

Reputation: 7 916

0

Python 3 + sympy, 72 bytes

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

Try it online!

Nick Kennedy

Posted 2019-09-23T01:46:54.880

Reputation: 11 829