[Update: D'oh -- sometimes I get so focused on something of interest in the OP's approach I can't see the forest for the trees. I should have thought, we can use Solve
, as shown below, because it's a polynomial...]
##Two##Two Three explanations##
There are twotwo three ways to explain why e /. x -> sol[[1]]
can result in a number larger than 10^166
when sol[[1]]
gives the best possible approximation of the root (at machine precision). For the sake of reproducibility, here is the code I used from the OP, with a slight change (Rationalize
did nothing on the coefficients generated):
SeedRandom[1];
(*r := Rationalize[RandomReal[NormalDistribution[0,1]]];*)
r := RandomReal[NormalDistribution[0, 1]];
e = randompol[100, 1];
sol = NSolve[e == 0, x];
###Update: Using Solve###
If we use Solve
on the exact equation, we can check these solutions against the ones returned by NSolve
. The equation has to have exact coefficients or Solve
uses numerical techniques.
solexact = Solve[SetPrecision[e, Infinity] == 0, x];
(x /. sol) == Sort@N[x /. solexact]
Sort@N[x /. solexact] - (x /. sol) // Abs // Max
(*
True
3.55271*10^-15
*)
Here we see Solve
did in fact return solutions (of course!).
ParallelMap[FullSimplify,
SetPrecision[e, Infinity] /. solexact] // AbsoluteTiming
(*
{77.192719, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0}}
*)
Perhaps the answer should stop here. Originally I was interested in explaining the numerics because this issue has come up before. I thought having an explanation of why NSolve
appears to have done a bad job but in fact did a good job might be helpful.
With the other roots, it is more or less the same, that (1) the computed number for x
is the best or nearly best possible approximation of the root and (2) the value of e
is due to a round-off error and/or a large value of D[e, x]
. About half give the best possible solution. In most other cases, the error is in the last one or two bits, but that might not be surprising given the sort of numerical difficulty e
presents. The worst cases are the complex conjugate pair sol[[{57, 58}]]
which are 12 ϵ
away from the bestbest exact solution (as found by FindRoot
FindRootSolve
). Below we see the value of e
is less at x - 12 eps
;
dxeps = MapThread[
Function[{solx, xexact},
Through[{Re, Im}[(x /. #xexact) - (x /. sol)]] /
{2^Floor@Log2@Abs[$MachineEpsilon Re[x]],
2^Floor@Log2@Abs[$$MachineEpsilon Re[x0]],
2^Floor@Log2@Abs[$MachineEpsilon Im[x]]Im[x0]]} /. sol &@
x0 -> x
FindRoot[SetPrecision[e],
Infinity], {x, x /. sol},
WorkingPrecisionSort@N[x ->/. 200]solexact]}
] /@ sol;
Update: Perhaps one should just use Solve
as above. I'll leave the explanation below because I find it interesting, even if it's rather useless in this case.