%mathpiper,def="FindRealRoots"

iDebug:=False;

//Retract("FindRealRoots",*);

FindRealRoots(_p) <--
[
    If(iDebug,Tell("FindRealRoots",p));
    Local(vars,var,cc,pp,vlcc,zeroRoot,minb,maxb,rr);
    vars := VarList(p);
    var  := vars[1];
    cc   := Content(p);
    pp   := PrimitivePart(p);
    If(iDebug,Tell("   ",{cc,pp}));
    vlcc := VarList(cc);
    If(Length(vlcc)>0 And Contains(vlcc,var), zeroRoot:=True,zeroRoot:=False);
    p:=SquareFree(Rationalize(pp));
    If(iDebug,Tell("   after sqf",p));
    minb := MinimumBound(p);
    maxb := MaximumBound(p);
    If(iDebug,Tell("   ",{minb,maxb}));
    rr := FindRealRoots(p,minb,maxb);
    If(zeroRoot,DestructiveAppend(rr,0));
    rr;
];


FindRealRoots(_p,_Mmin,_Mmax) <--
[
    If(iDebug,Tell("  FindRealRoots3",{p,Mmin,Mmax}));
    Local(bounds,result,i,prec,requiredPrec);
    bounds := BoundRealRoots(p,Mmin,Mmax);
    If(iDebug,Tell("      ",{bounds,Length(bounds)}));
    result:=FillList(0,Length(bounds));
    requiredPrec := BuiltinPrecisionGet();
    BuiltinPrecisionSet(BuiltinPrecisionGet()+4);
    prec:=10^-(requiredPrec+1);

    For(i:=1,i<=Length(bounds),i++)
    [
        If(iDebug,Tell(i));
        Local(a,b,c,r);
        {a,b} := bounds[i];
        c:=N(Eval((a+b)/2));
        If(iDebug,Tell("         ",{a,b,c}));
        r := Fail;
        If(iDebug,Tell("         newt1",`Hold(Newton(@p,x,@c,@prec,@a,@b))));
        if (a != b) [r := `Newton(@p,x,@c,prec,a,b);];
        If(iDebug,Tell("         newt2",r));
        if (r = Fail)
          [
             Local(c,cold,pa,pb,pc);
             pa:=(p Where x==a);
             pb:=(p Where x==b);
             c:=((a+b)/2);
             cold := a;
             While (Abs(cold-c)>prec)
             [
                 pc:=(p Where x==c);
                 If(iDebug,Tell("              ",{a,b,c}));
                 if (Abs(pc) < prec)
                   [ a:=c; b:=c; ]
                 else if (pa*pc < 0)
                   [ b:=c; pb:=pc; ]
                 else
                   [ a:=c; pa:=pc; ];
                   cold:=c;
                   c:=((a+b)/2);
             ];
             r:=c;
          ];
        result[i] := N(Eval((r/10)*(10)),requiredPrec);
    ];
    BuiltinPrecisionSet(requiredPrec);
    result;
];

%/mathpiper



%mathpiper_docs,name="FindRealRoots",categories="User Functions;Solvers (Numeric)"
*CMD FindRealRoots --- find the real roots of a polynomial
*STD
*CALL
	FindRealRoots(p)

*PARMS

{p} - a polynomial in {x}

*DESC

Return a list with the real roots of $ p $. It tries to find the real-valued
roots, and thus requires numeric floating point calculations. The precision
of the result can be improved by increasing the calculation precision.

*E.G. notest

In> p:=Expand((x+3.1)^5*(x-6.23))
Result: x^6+9.27*x^5-0.465*x^4-300.793*x^3-
	1394.2188*x^2-2590.476405*x-1783.5961073;
In> FindRealRoots(p)
Result: {-3.1,6.23};

*SEE SquareFree, RealRootsCount, MinimumBound, MaximumBound, Factor
%/mathpiper_docs