summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/polexpr
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/polexpr
Initial commit
Diffstat (limited to 'macros/latex/contrib/polexpr')
-rw-r--r--macros/latex/contrib/polexpr/README.md100
-rw-r--r--macros/latex/contrib/polexpr/polexpr.html2908
-rw-r--r--macros/latex/contrib/polexpr/polexpr.sty2946
-rw-r--r--macros/latex/contrib/polexpr/polexpr.txt2593
4 files changed, 8547 insertions, 0 deletions
diff --git a/macros/latex/contrib/polexpr/README.md b/macros/latex/contrib/polexpr/README.md
new file mode 100644
index 0000000000..29c0d2f5ab
--- /dev/null
+++ b/macros/latex/contrib/polexpr/README.md
@@ -0,0 +1,100 @@
+Package polexpr README
+======================
+
+License
+-------
+
+Copyright (C) 2018-2019 Jean-François Burnol
+
+See documentation of package [xint](http://www.ctan.org/pkg/xint) for
+contact information.
+
+This Work may be distributed and/or modified under the conditions of the
+LaTeX Project Public License version 1.3c. This version of this license
+is in
+
+> <http://www.latex-project.org/lppl/lppl-1-3c.txt>
+
+and version 1.3 or later is part of all distributions of LaTeX version
+2005/12/01 or later.
+
+This Work has the LPPL maintenance status author-maintained.
+
+The Author of this Work is Jean-François Burnol.
+
+This Work consists of the package file polexpr.sty, this README.md and
+the documentation file polexpr.txt.
+
+Abstract
+--------
+
+The package provides `\poldef`. This a parser of polynomial expressions
+based upon the `\xintdeffunc` mechanism of xintexpr.
+
+The parsed expressions use the operations of algebra (inclusive of
+composition of functions) with standard operators, fractional numbers
+(possibly in scientific notation) and previously defined polynomial
+functions or other constructs as recognized by the `\xintexpr` numerical
+parser.
+
+The polynomials are then not only genuine `\xintexpr` (and
+`\xintfloatexpr`) numerical functions but additionally are known to the
+package via their coefficients. This allows dedicated macros to
+implement polynomial algorithmics.
+
+Releases
+--------
+
+- 0.1 (2018/01/11)
+ Initial release (files README, polexpr.sty).
+- 0.2 (2018/01/14)
+ Documentation moved to polexpr.{txt,html}.
+- 0.3 (2018/01/17)
+ Make polynomials known to `\xintfloatexpr` and improve
+ documentation.
+- 0.3.1 (2018/01/18)
+ Fix two typos in documentation.
+- 0.4 (2018/02/16)
+ - Revert 0.3 automatic generation of floating point variants.
+ - Move CHANGE LOG from README.md to HTML documentation.
+ - A few bug fixes and breaking changes. Please refer to
+ `polexpr.html`.
+ - Main new feature: root localization via [Sturm
+ Theorem](https://en.wikipedia.org/wiki/Sturm%27s_theorem).
+- 0.4.1 (2018/03/01)
+ Synced with xint 1.3.
+- 0.4.2 (2018/03/03)
+ Documentation fix.
+- 0.5 (2018/04/08)
+ - new macros `\PolMakePrimitive` and `\PolIContent`.
+ - main (breaking) change: `\PolToSturm` creates a chain of primitive
+ integer coefficients polynomials.
+- 0.5.1 (2018/04/22)
+ The `'` character can be used in polynomial names.
+- 0.6 (2018/11/20)
+ New feature: multiplicity of roots.
+- 0.7 (2018/12/08), 0.7.1 (bugfix), 0.7.2 (bugfix) (2018/12/09)
+ New feature: finding all rational roots.
+- 0.7.3 (2019/02/04)
+ Bugfix: polynomial names ending in digits caused errors. Thanks to
+ Thomas Söll for report.
+- 0.7.4 (2019/02/12)
+ Bugfix: 20000000000 is too big for \numexpr, shouldn't I know that?
+ Thanks to Jürgen Gilg for report.
+
+Files of 0.7.4 release:
+
+- README.md,
+- polexpr.sty (package file),
+- polexpr.txt (documentation),
+- polexpr.html (conversion via
+ [DocUtils](http://docutils.sourceforge.net/docs/index.html)
+ rst2html.py)
+
+Acknowledgments
+---------------
+
+Thanks to Jürgen Gilg whose question about
+[xint](http://www.ctan.org/pkg/xint) usage for differentiating
+polynomials was the initial trigger leading to this package, and to
+Jürgen Gilg and Thomas Söll for testing it on some concrete problems.
diff --git a/macros/latex/contrib/polexpr/polexpr.html b/macros/latex/contrib/polexpr/polexpr.html
new file mode 100644
index 0000000000..6fc48c2dd6
--- /dev/null
+++ b/macros/latex/contrib/polexpr/polexpr.html
@@ -0,0 +1,2908 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" />
+<title>Package polexpr documentation</title>
+<style type="text/css">
+
+/*
+:Author: David Goodger (goodger@python.org)
+:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+ border: 0 }
+
+table.borderless td, table.borderless th {
+ /* Override padding for "table.docutils td" with "! important".
+ The right padding separates the table cells. */
+ padding: 0 0.5em 0 0 ! important }
+
+.first {
+ /* Override more specific margin styles with "! important". */
+ margin-top: 0 ! important }
+
+.last, .with-subtitle {
+ margin-bottom: 0 ! important }
+
+.hidden {
+ display: none }
+
+.subscript {
+ vertical-align: sub;
+ font-size: smaller }
+
+.superscript {
+ vertical-align: super;
+ font-size: smaller }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+blockquote.epigraph {
+ margin: 2em 5em ; }
+
+dl.docutils dd {
+ margin-bottom: 0.5em }
+
+object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
+ overflow: hidden;
+}
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+ font-weight: bold }
+*/
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title, .code .error {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+ compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+ margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+ margin-top: 0.5em }
+*/
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em ;
+ margin-right: 2em }
+
+div.footer, div.header {
+ clear: both;
+ font-size: smaller }
+
+div.line-block {
+ display: block ;
+ margin-top: 1em ;
+ margin-bottom: 1em }
+
+div.line-block div.line-block {
+ margin-top: 0 ;
+ margin-bottom: 0 ;
+ margin-left: 1.5em }
+
+div.sidebar {
+ margin: 0 0 0.5em 1em ;
+ border: medium outset ;
+ padding: 1em ;
+ background-color: #ffffee ;
+ width: 40% ;
+ float: right ;
+ clear: right }
+
+div.sidebar p.rubric {
+ font-family: sans-serif ;
+ font-size: medium }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+ margin-top: 0.4em }
+
+h1.title {
+ text-align: center }
+
+h2.subtitle {
+ text-align: center }
+
+hr.docutils {
+ width: 75% }
+
+img.align-left, .figure.align-left, object.align-left, table.align-left {
+ clear: left ;
+ float: left ;
+ margin-right: 1em }
+
+img.align-right, .figure.align-right, object.align-right, table.align-right {
+ clear: right ;
+ float: right ;
+ margin-left: 1em }
+
+img.align-center, .figure.align-center, object.align-center {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table.align-center {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.align-left {
+ text-align: left }
+
+.align-center {
+ clear: both ;
+ text-align: center }
+
+.align-right {
+ text-align: right }
+
+/* reset inner alignment in figures */
+div.align-right {
+ text-align: inherit }
+
+/* div.align-center * { */
+/* text-align: left } */
+
+.align-top {
+ vertical-align: top }
+
+.align-middle {
+ vertical-align: middle }
+
+.align-bottom {
+ vertical-align: bottom }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.attribution {
+ text-align: right ;
+ margin-left: 50% }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.rubric {
+ font-weight: bold ;
+ font-size: larger ;
+ color: maroon ;
+ text-align: center }
+
+p.sidebar-title {
+ font-family: sans-serif ;
+ font-weight: bold ;
+ font-size: larger }
+
+p.sidebar-subtitle {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+p.topic-title {
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font: inherit }
+
+pre.literal-block, pre.doctest-block, pre.math, pre.code {
+ margin-left: 2em ;
+ margin-right: 2em }
+
+pre.code .ln { color: grey; } /* line numbers */
+pre.code, code { background-color: #eeeeee }
+pre.code .comment, code .comment { color: #5C6576 }
+pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
+pre.code .literal.string, code .literal.string { color: #0C5404 }
+pre.code .name.builtin, code .name.builtin { color: #352B84 }
+pre.code .deleted, code .deleted { background-color: #DEB0A1}
+pre.code .inserted, code .inserted { background-color: #A3D289}
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option {
+ white-space: nowrap }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+span.section-subtitle {
+ /* font-size relative to parent (h1..h6 element) */
+ font-size: 80% }
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.docutils {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.footnote {
+ border-left: solid 1px black;
+ margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap ;
+ padding-left: 0 }
+
+/* "booktabs" style (no vertical lines) */
+table.docutils.booktabs {
+ border: 0px;
+ border-top: 2px solid;
+ border-bottom: 2px solid;
+ border-collapse: collapse;
+}
+table.docutils.booktabs * {
+ border: 0px;
+}
+table.docutils.booktabs th {
+ border-bottom: thin solid;
+ text-align: left;
+}
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+ font-size: 100% }
+
+ul.auto-toc {
+ list-style-type: none }
+
+</style>
+</head>
+<body>
+<div class="document" id="package-polexpr-documentation">
+<h1 class="title">Package polexpr documentation</h1>
+<h2 class="subtitle" id="id1">0.7.4 (2019/02/12)</h2>
+
+<!-- comment: -*- fill-column: 72; mode: rst; -*- -->
+<div class="contents topic" id="contents">
+<p class="topic-title first">Contents</p>
+<ul class="simple">
+<li><a class="reference internal" href="#basic-syntax" id="id38">Basic syntax</a></li>
+<li><a class="reference internal" href="#examples-of-localization-of-roots" id="id39">Examples of localization of roots</a><ul>
+<li><a class="reference internal" href="#a-typical-example" id="id40">A typical example</a></li>
+<li><a class="reference internal" href="#a-degree-four-polynomial-with-nearby-roots" id="id41">A degree four polynomial with nearby roots</a></li>
+<li><a class="reference internal" href="#the-degree-nine-polynomial-with-0-99-0-999-0-9999-as-triple-roots" id="id42">The degree nine polynomial with 0.99, 0.999, 0.9999 as triple roots</a></li>
+<li><a class="reference internal" href="#a-degree-five-polynomial-with-three-rational-roots" id="id43">A degree five polynomial with three rational roots</a></li>
+<li><a class="reference internal" href="#a-mignotte-type-polynomial" id="id44">A Mignotte type polynomial</a></li>
+<li><a class="reference internal" href="#the-wilkinson-polynomial" id="id45">The Wilkinson polynomial</a></li>
+<li><a class="reference internal" href="#the-second-wilkinson-polynomial" id="id46">The second Wilkinson polynomial</a></li>
+<li><a class="reference internal" href="#the-degree-41-polynomial-with-2-1-9-1-8-0-0-1-1-9-2-as-roots" id="id47">The degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., 1.9, 2 as roots</a></li>
+<li><a class="reference internal" href="#roots-of-chebyshev-polynomials" id="id48">Roots of Chebyshev polynomials</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#non-expandable-macros" id="id49">Non-expandable macros</a><ul>
+<li><a class="reference internal" href="#poldef-polname-letter-expression-in-letter" id="id50"><tt class="docutils literal">\poldef <span class="pre">polname(letter):=</span> expression in letter;</tt></a></li>
+<li><a class="reference internal" href="#poldef-letter-polname-expression-in-letter" id="id51"><tt class="docutils literal"><span class="pre">\PolDef[letter]{polname}{expression</span> in letter}</tt></a></li>
+<li><a class="reference internal" href="#polgenfloatvariant-polname" id="id52"><tt class="docutils literal">\PolGenFloatVariant{polname}</tt></a></li>
+<li><a class="reference internal" href="#pollet-polname-2-polname-1" id="id53"><tt class="docutils literal"><span class="pre">\PolLet{polname_2}={polname_1}</span></tt></a></li>
+<li><a class="reference internal" href="#polgloballet-polname-2-polname-1" id="id54"><tt class="docutils literal"><span class="pre">\PolGlobalLet{polname_2}={polname_1}</span></tt></a></li>
+<li><a class="reference internal" href="#polassign-polname-toarray-macro" id="id55"><tt class="docutils literal"><span class="pre">\PolAssign{polname}\toarray\macro</span></tt></a></li>
+<li><a class="reference internal" href="#polget-polname-fromarray-macro" id="id56"><tt class="docutils literal"><span class="pre">\PolGet{polname}\fromarray\macro</span></tt></a></li>
+<li><a class="reference internal" href="#polfromcsv-polname-csv" id="id57"><tt class="docutils literal"><span class="pre">\PolFromCSV{polname}{&lt;csv&gt;}</span></tt></a></li>
+<li><a class="reference internal" href="#poltypeset-polname" id="id58"><tt class="docutils literal">\PolTypeset{polname}</tt></a><ul>
+<li><a class="reference internal" href="#poltypesetcmd-raw-coeff" id="id59"><tt class="docutils literal">\PolTypesetCmd{raw_coeff}</tt></a></li>
+<li><a class="reference internal" href="#poltypesetone-raw-coeff" id="id60"><tt class="docutils literal">\PolTypesetOne{raw_coeff}</tt></a></li>
+<li><a class="reference internal" href="#id6" id="id61"><tt class="docutils literal">\PolTypesetMonomialCmd</tt></a></li>
+<li><a class="reference internal" href="#poltypesetcmdprefix-raw-coeff" id="id62"><tt class="docutils literal">\PolTypesetCmdPrefix{raw_coeff}</tt></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#id8" id="id63"><tt class="docutils literal"><span class="pre">\PolTypeset*{polname}</span></tt></a></li>
+<li><a class="reference internal" href="#poldiff-polname-1-polname-2" id="id64"><tt class="docutils literal"><span class="pre">\PolDiff{polname_1}{polname_2}</span></tt></a></li>
+<li><a class="reference internal" href="#poldiff-n-polname-1-polname-2" id="id65"><tt class="docutils literal"><span class="pre">\PolDiff[N]{polname_1}{polname_2}</span></tt></a></li>
+<li><a class="reference internal" href="#polantidiff-polname-1-polname-2" id="id66"><tt class="docutils literal"><span class="pre">\PolAntiDiff{polname_1}{polname_2}</span></tt></a></li>
+<li><a class="reference internal" href="#polantidiff-n-polname-1-polname-2" id="id67"><tt class="docutils literal"><span class="pre">\PolAntiDiff[N]{polname_1}{polname_2}</span></tt></a></li>
+<li><a class="reference internal" href="#poldivide-polname-1-polname-2-polname-q-polname-r" id="id68"><tt class="docutils literal"><span class="pre">\PolDivide{polname_1}{polname_2}{polname_Q}{polname_R}</span></tt></a></li>
+<li><a class="reference internal" href="#polquo-polname-1-polname-2-polname-q" id="id69"><tt class="docutils literal"><span class="pre">\PolQuo{polname_1}{polname_2}{polname_Q}</span></tt></a></li>
+<li><a class="reference internal" href="#polrem-polname-1-polname-2-polname-r" id="id70"><tt class="docutils literal"><span class="pre">\PolRem{polname_1}{polname_2}{polname_R}</span></tt></a></li>
+<li><a class="reference internal" href="#polgcd-polname-1-polname-2-polname-gcd" id="id71"><tt class="docutils literal"><span class="pre">\PolGCD{polname_1}{polname_2}{polname_GCD}</span></tt></a></li>
+<li><a class="reference internal" href="#poltosturm-polname-sturmname" id="id72"><tt class="docutils literal"><span class="pre">\PolToSturm{polname}{sturmname}</span></tt></a></li>
+<li><a class="reference internal" href="#id10" id="id73"><tt class="docutils literal"><span class="pre">\PolToSturm*{polname}{sturmname}</span></tt></a></li>
+<li><a class="reference internal" href="#polsettosturmchainsignchangesat-macro-sturmname-fraction" id="id74"><tt class="docutils literal"><span class="pre">\PolSetToSturmChainSignChangesAt{\macro}{sturmname}{fraction}</span></tt></a></li>
+<li><a class="reference internal" href="#polsettonbofzeroswithin-macro-sturmname-value-a-value-b" id="id75"><tt class="docutils literal"><span class="pre">\PolSetToNbOfZerosWithin{\macro}{sturmname}{value_a}{value_b}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmisolatezeros-sturmname" id="id76"><tt class="docutils literal">\PolSturmIsolateZeros{sturmname}</tt></a></li>
+<li><a class="reference internal" href="#id12" id="id77"><tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros*{sturmname}</span></tt></a></li>
+<li><a class="reference internal" href="#id14" id="id78"><tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros**{sturmname}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmisolatezerosandgetmultiplicities-sturmname" id="id79"><tt class="docutils literal">\PolSturmIsolateZerosAndGetMultiplicities{sturmname}</tt></a></li>
+<li><a class="reference internal" href="#polsturmisolatezerosgetmultiplicitiesandrationalroots-sturmname" id="id80"><tt class="docutils literal">\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{sturmname}</tt></a></li>
+<li><a class="reference internal" href="#polsturmisolatezerosandfindrationalroots-sturmname" id="id81"><tt class="docutils literal">\PolSturmIsolateZerosAndFindRationalRoots{sturmname}</tt></a></li>
+<li><a class="reference internal" href="#polrefineinterval-sturmname-index" id="id82"><tt class="docutils literal"><span class="pre">\PolRefineInterval*{sturmname}{index}</span></tt></a></li>
+<li><a class="reference internal" href="#polrefineinterval-n-sturmname-index" id="id83"><tt class="docutils literal"><span class="pre">\PolRefineInterval[N]{sturmname}{index}</span></tt></a></li>
+<li><a class="reference internal" href="#polensureintervallength-sturmname-index-e" id="id84"><tt class="docutils literal"><span class="pre">\PolEnsureIntervalLength{sturmname}{index}{E}</span></tt></a></li>
+<li><a class="reference internal" href="#polensureintervallengths-sturmname-e" id="id85"><tt class="docutils literal"><span class="pre">\PolEnsureIntervalLengths{sturmname}{E}</span></tt></a></li>
+<li><a class="reference internal" href="#polprintintervals-varname-sturmname" id="id86"><tt class="docutils literal"><span class="pre">\PolPrintIntervals[varname]{sturmname}</span></tt></a><ul>
+<li><a class="reference internal" href="#polprintintervalsnorealroots" id="id87"><tt class="docutils literal">\PolPrintIntervalsNoRealRoots</tt></a></li>
+<li><a class="reference internal" href="#polprintintervalsbeginenv" id="id88"><tt class="docutils literal">\PolPrintIntervalsBeginEnv</tt></a></li>
+<li><a class="reference internal" href="#polprintintervalsendenv" id="id89"><tt class="docutils literal">\PolPrintIntervalsEndEnv</tt></a></li>
+<li><a class="reference internal" href="#polprintintervalsknownroot" id="id90"><tt class="docutils literal">\PolPrintIntervalsKnownRoot</tt></a></li>
+<li><a class="reference internal" href="#polprintintervalsunknownroot" id="id91"><tt class="docutils literal">\PolPrintIntervalsUnknownRoot</tt></a></li>
+<li><a class="reference internal" href="#id15" id="id92"><tt class="docutils literal">\PolPrintIntervalsPrintExactZero</tt></a></li>
+<li><a class="reference internal" href="#id16" id="id93"><tt class="docutils literal">\PolPrintIntervalsPrintLeftEndPoint</tt></a></li>
+<li><a class="reference internal" href="#id17" id="id94"><tt class="docutils literal">\PolPrintIntervalsPrintRightEndPoint</tt></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#id19" id="id95"><tt class="docutils literal"><span class="pre">\PolPrintIntervals*[varname]{sturmname}</span></tt></a><ul>
+<li><a class="reference internal" href="#polprintintervalsprintmultiplicity" id="id96"><tt class="docutils literal">\PolPrintIntervalsPrintMultiplicity</tt></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#polmapcoeffs-macro-polname" id="id97"><tt class="docutils literal"><span class="pre">\PolMapCoeffs{\macro}{polname}</span></tt></a></li>
+<li><a class="reference internal" href="#polreducecoeffs-polname" id="id98"><tt class="docutils literal">\PolReduceCoeffs{polname}</tt></a></li>
+<li><a class="reference internal" href="#id21" id="id99"><tt class="docutils literal"><span class="pre">\PolReduceCoeffs*{polname}</span></tt></a></li>
+<li><a class="reference internal" href="#polmakemonic-polname" id="id100"><tt class="docutils literal">\PolMakeMonic{polname}</tt></a></li>
+<li><a class="reference internal" href="#polmakeprimitive-polname" id="id101"><tt class="docutils literal">\PolMakePrimitive{polname}</tt></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#expandable-macros" id="id102">Expandable macros</a><ul>
+<li><a class="reference internal" href="#poleval-polname-atexpr-numerical-expression" id="id103"><tt class="docutils literal"><span class="pre">\PolEval{polname}\AtExpr{numerical</span> expression}</tt></a></li>
+<li><a class="reference internal" href="#poleval-polname-at-fraction" id="id104"><tt class="docutils literal"><span class="pre">\PolEval{polname}\At{fraction}</span></tt></a></li>
+<li><a class="reference internal" href="#polevalreduced-polname-atexpr-numerical-expression" id="id105"><tt class="docutils literal"><span class="pre">\PolEvalReduced{polname}\AtExpr{numerical</span> expression}</tt></a></li>
+<li><a class="reference internal" href="#polevalreduced-polname-at-fraction" id="id106"><tt class="docutils literal"><span class="pre">\PolEvalReduced{polname}\At{fraction}</span></tt></a></li>
+<li><a class="reference internal" href="#polfloateval-polname-atexpr-numerical-expression" id="id107"><tt class="docutils literal"><span class="pre">\PolFloatEval{polname}\AtExpr{numerical</span> expression}</tt></a></li>
+<li><a class="reference internal" href="#polfloateval-polname-at-fraction" id="id108"><tt class="docutils literal"><span class="pre">\PolFloatEval{polname}\At{fraction}</span></tt></a></li>
+<li><a class="reference internal" href="#polifcoeffisplusorminusone-a-b" id="id109"><tt class="docutils literal"><span class="pre">\PolIfCoeffIsPlusOrMinusOne{A}{B}</span></tt></a></li>
+<li><a class="reference internal" href="#polleadingcoeff-polname" id="id110"><tt class="docutils literal">\PolLeadingCoeff{polname}</tt></a></li>
+<li><a class="reference internal" href="#polnthcoeff-polname-number" id="id111"><tt class="docutils literal"><span class="pre">\PolNthCoeff{polname}{number}</span></tt></a></li>
+<li><a class="reference internal" href="#poldegree-polname" id="id112"><tt class="docutils literal">\PolDegree{polname}</tt></a></li>
+<li><a class="reference internal" href="#policontent-polname" id="id113"><tt class="docutils literal">\PolIContent{polname}</tt></a></li>
+<li><a class="reference internal" href="#poltoexpr-polname" id="id114"><tt class="docutils literal">\PolToExpr{polname}</tt></a><ul>
+<li><a class="reference internal" href="#poltoexproneterm-raw-coeff-number" id="id115"><tt class="docutils literal"><span class="pre">\PolToExprOneTerm{raw_coeff}{number}</span></tt></a></li>
+<li><a class="reference internal" href="#poltoexpronetermstylea-raw-coeff-number" id="id116"><tt class="docutils literal"><span class="pre">\PolToExprOneTermStyleA{raw_coeff}{number}</span></tt></a></li>
+<li><a class="reference internal" href="#poltoexpronetermstyleb-raw-coeff-number" id="id117"><tt class="docutils literal"><span class="pre">\PolToExprOneTermStyleB{raw_coeff}{number}</span></tt></a></li>
+<li><a class="reference internal" href="#poltoexprcmd-raw-coeff" id="id118"><tt class="docutils literal">\PolToExprCmd{raw_coeff}</tt></a></li>
+<li><a class="reference internal" href="#poltoexprtermprefix-raw-coeff" id="id119"><tt class="docutils literal">\PolToExprTermPrefix{raw_coeff}</tt></a></li>
+<li><a class="reference internal" href="#id28" id="id120"><tt class="docutils literal">\PolToExprVar</tt></a></li>
+<li><a class="reference internal" href="#id29" id="id121"><tt class="docutils literal">\PolToExprTimes</tt></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#id31" id="id122"><tt class="docutils literal"><span class="pre">\PolToExpr*{polname}</span></tt></a></li>
+<li><a class="reference internal" href="#poltofloatexpr-polname" id="id123"><tt class="docutils literal">\PolToFloatExpr{polname}</tt></a><ul>
+<li><a class="reference internal" href="#poltofloatexproneterm-raw-coeff-number" id="id124"><tt class="docutils literal"><span class="pre">\PolToFloatExprOneTerm{raw_coeff}{number}</span></tt></a></li>
+<li><a class="reference internal" href="#poltofloatexprcmd-raw-coeff" id="id125"><tt class="docutils literal">\PolToFloatExprCmd{raw_coeff}</tt></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#id35" id="id126"><tt class="docutils literal"><span class="pre">\PolToFloatExpr*{polname}</span></tt></a></li>
+<li><a class="reference internal" href="#poltolist-polname" id="id127"><tt class="docutils literal">\PolToList{polname}</tt></a></li>
+<li><a class="reference internal" href="#poltocsv-polname" id="id128"><tt class="docutils literal">\PolToCSV{polname}</tt></a></li>
+<li><a class="reference internal" href="#polsturmchainlength-sturmname" id="id129"><tt class="docutils literal">\PolSturmChainLength{sturmname}</tt></a></li>
+<li><a class="reference internal" href="#polsturmifzeroexactlyknown-sturmname-index-a-b" id="id130"><tt class="docutils literal"><span class="pre">\PolSturmIfZeroExactlyKnown{sturmname}{index}{A}{B}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmisolatedzeroleft-sturmname-index" id="id131"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroLeft{sturmname}{index}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmisolatedzeroright-sturmname-index" id="id132"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroRight{sturmname}{index}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmisolatedzeromultiplicity-sturmname-index" id="id133"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroMultiplicity{sturmname}{index}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmnbofisolatedzeros-sturmname" id="id134"><tt class="docutils literal">\PolSturmNbOfIsolatedZeros{sturmname}</tt></a><ul>
+<li><a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequalto-value" id="id135"><tt class="docutils literal"><span class="pre">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequaltoexpr-expression" id="id136"><tt class="docutils literal"><span class="pre">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmnbwithmultofrootsof-sturmname-lessthanorequalto-value" id="id137"><tt class="docutils literal"><span class="pre">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualTo{value}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmnbwithmultofrootsof-sturmname-lessthanorequaltoexpr-expression" id="id138"><tt class="docutils literal"><span class="pre">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</span></tt></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#polsturmnbofrationalroots-sturmname" id="id139"><tt class="docutils literal">\PolSturmNbOfRationalRoots{sturmname}</tt></a></li>
+<li><a class="reference internal" href="#polsturmnbofrationalrootswithmultiplicities-sturmname" id="id140"><tt class="docutils literal">\PolSturmNbOfRationalRootsWithMultiplicities{sturmname}</tt></a></li>
+<li><a class="reference internal" href="#polsturmrationalroot-sturmname-k" id="id141"><tt class="docutils literal"><span class="pre">\PolSturmRationalRoot{sturmname}{k}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmrationalrootindex-sturmname-k" id="id142"><tt class="docutils literal"><span class="pre">\PolSturmRationalRootIndex{sturmname}{k}</span></tt></a></li>
+<li><a class="reference internal" href="#polsturmrationalrootmultiplicity-sturmname-k" id="id143"><tt class="docutils literal"><span class="pre">\PolSturmRationalRootMultiplicity{sturmname}{k}</span></tt></a></li>
+<li><a class="reference internal" href="#polintervalwidth-sturmname-index" id="id144"><tt class="docutils literal"><span class="pre">\PolIntervalWidth{sturmname}{index}</span></tt></a></li>
+<li><a class="reference internal" href="#expandable-macros-for-use-within-execution-of-polprintintervals" id="id145">Expandable macros for use within execution of <tt class="docutils literal">\PolPrintIntervals</tt></a><ul>
+<li><a class="reference internal" href="#polprintintervalsthevar" id="id146"><tt class="docutils literal">\PolPrintIntervalsTheVar</tt></a></li>
+<li><a class="reference internal" href="#polprintintervalstheindex" id="id147"><tt class="docutils literal">\PolPrintIntervalsTheIndex</tt></a></li>
+<li><a class="reference internal" href="#polprintintervalsthesturmname" id="id148"><tt class="docutils literal">\PolPrintIntervalsTheSturmName</tt></a></li>
+<li><a class="reference internal" href="#polprintintervalstheleftendpoint" id="id149"><tt class="docutils literal">\PolPrintIntervalsTheLeftEndPoint</tt></a></li>
+<li><a class="reference internal" href="#polprintintervalstherightendpoint" id="id150"><tt class="docutils literal">\PolPrintIntervalsTheRightEndPoint</tt></a></li>
+<li><a class="reference internal" href="#polprintintervalsthemultiplicity" id="id151"><tt class="docutils literal">\PolPrintIntervalsTheMultiplicity</tt></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#poldectostring-decimal-number" id="id152"><tt class="docutils literal">\PolDecToString{decimal number}</tt></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#booleans-with-default-setting-as-indicated" id="id153">Booleans (with default setting as indicated)</a><ul>
+<li><a class="reference internal" href="#xintverbosefalse" id="id154"><tt class="docutils literal">\xintverbosefalse</tt></a></li>
+<li><a class="reference internal" href="#poltypesetallfalse" id="id155"><tt class="docutils literal">\poltypesetallfalse</tt></a></li>
+<li><a class="reference internal" href="#poltoexprallfalse" id="id156"><tt class="docutils literal">\poltoexprallfalse</tt></a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#polexprsetup" id="id157"><tt class="docutils literal">\polexprsetup</tt></a></li>
+<li><a class="reference internal" href="#technicalities" id="id158">Technicalities</a></li>
+<li><a class="reference internal" href="#change-log" id="id159">CHANGE LOG</a></li>
+<li><a class="reference internal" href="#acknowledgments" id="id160">Acknowledgments</a></li>
+</ul>
+</div>
+<div class="section" id="basic-syntax">
+<h1><a class="toc-backref" href="#id38">Basic syntax</a></h1>
+<p>The syntax is:</p>
+<pre class="literal-block">
+\poldef polname(x):= expression in variable x;
+</pre>
+<p>where:</p>
+<ul class="simple">
+<li>in place of <tt class="docutils literal">x</tt> an arbitrary <em>dummy variable</em> is authorized,
+i.e. per default any of <tt class="docutils literal"><span class="pre">[a-z|A-Z]</span></tt> (more letters can be declared
+under Unicode engines.)</li>
+<li><tt class="docutils literal">polname</tt> consists of letters, digits, and the <tt class="docutils literal">_</tt> and
+<tt class="docutils literal">'</tt> characters. It must start with a letter.</li>
+</ul>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last">The <tt class="docutils literal">'</tt> is authorized since <tt class="docutils literal">0.5.1</tt>. As a result some constructs
+recognized by the <tt class="docutils literal">\xintexpr</tt> parser, such as <tt class="docutils literal">var1 'and' var2</tt>
+will get misinterpreted and cause errors. However these constructs
+are unlikely to be frequently needed in polynomial expressions, and
+the <tt class="docutils literal">\xintexpr</tt> syntax offers alternatives, so it was deemed a
+small evil. Of course the <tt class="docutils literal">\xintexpr</tt> parser is modified only
+temporarily during execution of <tt class="docutils literal">\poldef</tt>.</p>
+</div>
+<p>One can also issue:</p>
+<pre class="literal-block">
+\PolDef{polname}{expression in variable x}
+</pre>
+<p>which admits an optional first argument to modify the variable letter
+from its default <tt class="docutils literal">x</tt>.</p>
+<dl class="docutils">
+<dt><tt class="docutils literal">\poldef <span class="pre">f(x):=</span> <span class="pre">1-x+x^2;</span></tt></dt>
+<dd>defines polynomial <tt class="docutils literal">f</tt>. Polynomial names must start with a
+letter and may contain letters, digits, underscores and the right
+tick character. The
+variable must be a single letter. The colon character is optional.
+The semi-colon at end of expression is mandatory.</dd>
+<dt><tt class="docutils literal"><span class="pre">\PolDef{f}{1-x+x^2}</span></tt></dt>
+<dd>does the same as <tt class="docutils literal">\poldef <span class="pre">f(x):=</span> <span class="pre">1-x+x^2;</span></tt> To use another letter
+than <tt class="docutils literal">x</tt> in the expression, one must pass it as an extra optional
+argument to <tt class="docutils literal">\PolDef</tt>. Useful if the semi-colon has been assigned
+some non-standard catcode by some package.</dd>
+<dt><tt class="docutils literal"><span class="pre">\PolLet{g}={f}</span></tt></dt>
+<dd>saves a copy of <tt class="docutils literal">f</tt> under name <tt class="docutils literal">g</tt>. Also usable without <tt class="docutils literal">=</tt>.</dd>
+<dt><tt class="docutils literal">\poldef <span class="pre">f(z):=</span> <span class="pre">f(z)^2;</span></tt></dt>
+<dd>redefines <tt class="docutils literal">f</tt> in terms of itself.</dd>
+<dt><tt class="docutils literal">\poldef <span class="pre">f(T):=</span> <span class="pre">f(f(T));</span></tt></dt>
+<dd>again redefines <tt class="docutils literal">f</tt> in terms of its (new) self.</dd>
+<dt><tt class="docutils literal">\poldef <span class="pre">k(z):=</span> <span class="pre">f(z)-g(g(z)^2)^2;</span></tt></dt>
+<dd>should now define the zero polynomial... Let's check:
+<tt class="docutils literal">\[ k(z) = <span class="pre">\PolTypeset[z]{k}</span> \]</tt></dd>
+<dt><tt class="docutils literal"><span class="pre">\PolDiff{f}{f'}</span></tt></dt>
+<dd>sets <tt class="docutils literal">f'</tt> to the derivative of <tt class="docutils literal">f</tt>. The name doesn't have to be
+<tt class="docutils literal">f'</tt> (in fact the <tt class="docutils literal">'</tt> is licit only since <tt class="docutils literal">0.5.1</tt>).</dd>
+</dl>
+<div class="admonition important">
+<p class="first admonition-title">Important</p>
+<p class="last">This is not done automatically. If some new definition needs to use
+the derivative of some available polynomial, that derivative
+polynomial must have been defined via <tt class="docutils literal">\PolDiff</tt>: something like
+<tt class="docutils literal"><span class="pre">T'(x)^2</span></tt> will not work without a prior <tt class="docutils literal"><span class="pre">\PolDiff{T}{T'}</span></tt>.</p>
+</div>
+<dl class="docutils">
+<dt><tt class="docutils literal"><span class="pre">\PolDiff{f'}{f''}</span></tt></dt>
+<dd>obtains second derivative.</dd>
+<dt><tt class="docutils literal"><span class="pre">\PolDiff[3]{f}{f'''}</span></tt></dt>
+<dd>computes the third derivative.</dd>
+</dl>
+<pre class="literal-block">
+$f(z) = \PolTypeset[z]{f} $\newline
+$f'(z) = \PolTypeset[z]{f'} $\newline
+$f''(z) = \PolTypeset[z]{f''} $\newline
+$f'''(z)= \PolTypeset[z]{f'''} $\par
+</pre>
+<div class="admonition important">
+<p class="first admonition-title">Important</p>
+<p>The package does not currently know rational functions: <tt class="docutils literal">/</tt> in
+a parsed polynomial expression does the Euclidean quotient:</p>
+<pre class="literal-block">
+(1-x^2)/(1-x)
+</pre>
+<p>does give <tt class="docutils literal">1+x</tt> but</p>
+<pre class="literal-block">
+(1/(1-x))*(1-x^2)
+</pre>
+<p>evaluates to zero. This will work as expected:</p>
+<pre class="last literal-block">
+\poldef k(x):= (x-1)(x-2)(x-3)(x-4)/(x^2-5x+4);
+</pre>
+</div>
+<div class="admonition attention" id="warningtacit">
+<p class="first admonition-title">Attention!</p>
+<p><tt class="docutils literal">1/2 x^2</tt> skips the space and is treated like <tt class="docutils literal"><span class="pre">1/(2*x^2)</span></tt> because
+of the tacit multiplication rules of xintexpr. But this means it
+gives zero! Thus one must use <tt class="docutils literal">(1/2)x^2</tt> or <tt class="docutils literal">1/2*x^2</tt> or
+<tt class="docutils literal"><span class="pre">(1/2)*x^2</span></tt> for disambiguation: <tt class="docutils literal">x - 1/2*x^2 + <span class="pre">1/3*x^3...</span></tt>. It is
+even simpler to move the denominator to the right: <tt class="docutils literal">x - x^2/2 +
+x^3/3 - ...</tt>.</p>
+<p class="last">It is worth noting that <tt class="docutils literal"><span class="pre">1/2(x-1)(x-2)</span></tt> suffers the same issue:
+<a class="reference external" href="http://www.ctan.org/pkg/xint">xint</a> tacit multiplication always &quot;ties more&quot;, hence this gets
+interpreted as <tt class="docutils literal"><span class="pre">1/(2*(x-1)*(x-2))</span></tt> which gives zero by polynomial
+division. Thus, use one of <tt class="docutils literal"><span class="pre">(1/2)(x-1)(x-2)</span></tt>, <tt class="docutils literal"><span class="pre">1/2*(x-1)(x-2)</span></tt> or
+<tt class="docutils literal"><span class="pre">(x-1)(x-2)/2</span></tt>.</p>
+</div>
+<p>After:</p>
+<pre class="literal-block">
+\poldef f_1(x):= 25(x-1)(x^2-2)(x-3)(x-4)(x-5);%
+\poldef f_2(x):= 37(x-1)(x^2-2)(x-6)(x-7)(x-8);%
+</pre>
+<p>the macro call <tt class="docutils literal"><span class="pre">\PolGCD{f_1}{f_2}{k}</span></tt> sets <tt class="docutils literal">k</tt> to the (unitary) GCD of
+<tt class="docutils literal">f_1</tt> and <tt class="docutils literal">f_2</tt> (hence to the expansion of <tt class="docutils literal"><span class="pre">(x-1)(x^2-2)</span></tt>.)</p>
+<dl class="docutils">
+<dt><tt class="docutils literal">\PolToExpr{k}</tt></dt>
+<dd>will (expandably) give in this case <tt class="docutils literal"><span class="pre">x^3-x^2-2*x+2</span></tt>. This is
+useful for console or file output (the syntax is Maple- and
+PSTricks-compatible; the letter used in output can be
+(non-expandably) changed via a redefinition of <a class="reference internal" href="#poltoexprvar">\PolToExprVar</a>.)</dd>
+<dt><tt class="docutils literal"><span class="pre">\PolToExpr*{k}</span></tt></dt>
+<dd>gives ascending powers: <tt class="docutils literal"><span class="pre">2-2*x-x^2+x^3</span></tt>.</dd>
+</dl>
+</div>
+<div class="section" id="examples-of-localization-of-roots">
+<h1><a class="toc-backref" href="#id39">Examples of localization of roots</a></h1>
+<ul>
+<li><p class="first">To make printed decimal numbers more enjoyable than via
+<tt class="docutils literal">\xintSignedFrac</tt>:</p>
+<pre class="literal-block">
+\renewcommand\PolTypesetOne[1]{\PolDecToString{\xintREZ{#1}}}%
+</pre>
+<p><tt class="docutils literal">\PolDecToString</tt> will use decimal notation to incorporate the power
+of ten part; and the <tt class="docutils literal">\xintREZ</tt> will have the effect to suppress
+trailing zeros if present in raw numerator (if those digits end up
+after decimal mark.) Notice that the above are expandable macros and
+that one can also do:</p>
+<pre class="literal-block">
+\renewcommand\PolToExprCmd[1]{\PolDecToString{\xintREZ{#1}}}%
+</pre>
+<p>to modify output of <a class="reference internal" href="#poltoexpr-polname">\PolToExpr{polname}</a>.</p>
+</li>
+<li><p class="first">For extra info in log file use <tt class="docutils literal">\xintverbosetrue</tt>.</p>
+</li>
+<li><p class="first">Only for some of these examples is the output included here.</p>
+</li>
+</ul>
+<div class="section" id="a-typical-example">
+<h2><a class="toc-backref" href="#id40">A typical example</a></h2>
+<p>In this example the polynomial is square-free.</p>
+<pre class="literal-block">
+\poldef f(x) := x^7 - x^6 - 2x + 1;
+
+\PolToSturm{f}{f}
+\PolSturmIsolateZeros{f}
+The \PolTypeset{f} polynomial has \PolSturmNbOfIsolatedZeros{f} distinct real
+roots which are located in the following intervals:
+\PolPrintIntervals{f}
+Here is the second root with ten more decimal digits:
+\PolRefineInterval[10]{f}{2}
+\[\PolSturmIsolatedZeroLeft{f}{2}&lt;Z_2&lt;\PolSturmIsolatedZeroRight{f}{2}\]
+And here is the first root with twenty digits after decimal mark:
+\PolEnsureIntervalLength{f}{1}{-20}
+\[\PolSturmIsolatedZeroLeft{f}{1}&lt;Z_1&lt;\PolSturmIsolatedZeroRight{f}{1}\]
+The first element of the Sturm chain has degree $\PolDegree{f_0}$. As
+this is the original degreee $\PolDegree{f}$ we know that $f$ is square free.
+Its derivative is up to a constant \PolTypeset{f_1} (in this example
+it is identical with it).
+\PolToSturm{f_1}{f_1}\PolSturmIsolateZeros{f_1}%
+The derivative has \PolSturmNbOfIsolatedZeros{f_1} distinct real
+roots:
+\PolPrintIntervals[W]{f_1}
+\PolEnsureIntervalLengths{f_1}{-10}%
+Here they are with ten digits after decimal mark:
+\PolPrintIntervals[W]{f_1}
+\PolDiff{f_1}{f''}
+\PolToSturm{f''}{f''}
+\PolSturmIsolateZeros{f''}
+The second derivative is \PolTypeset{f''}.
+It has \PolSturmNbOfIsolatedZeros{f''} distinct real
+roots:
+\PolPrintIntervals[X]{f''}
+Here is the positive one with 20 digits after decimal mark:
+\PolEnsureIntervalLength{f''}{2}{-20}%
+\[X_2 = \PolSturmIsolatedZeroLeft{f''}{2}\dots\]
+The more mathematically advanced among our dear readers will be able
+to give the exact value for $X_2$!
+</pre>
+</div>
+<div class="section" id="a-degree-four-polynomial-with-nearby-roots">
+<h2><a class="toc-backref" href="#id41">A degree four polynomial with nearby roots</a></h2>
+<p>Notice that this example is a bit outdated as <tt class="docutils literal">0.7</tt> release has
+added <tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros**{sturmname}</span></tt> which would find exactly
+the roots. The steps here retain their interest when one is interested
+in finding isolating intervals for example to prepare some demonstration
+of dichotomy method.</p>
+<pre class="literal-block">
+\PolDef{Q}{(x-1.050001)(x-1.105001)(x-1.110501)(x-1.111051)}
+\PolTypeset{Q}
+\PolToSturm{Q}{Q} % it is allowed to use same prefix for Sturm chain
+\PolSturmIsolateZeros{Q}
+\PolPrintIntervals{Q}
+% reports 1.0 &lt; Z_1 &lt; 1.1, 1.10 &lt; Z_2 &lt; 1.11, 1.110 &lt; Z_3 &lt; 1.111, and 1.111 &lt; Z_4 &lt; 1.112
+% but the above bounds do not allow minimizing separation between roots
+% so we refine:
+\PolRefineInterval*{Q}{1}
+\PolRefineInterval*{Q}{2}
+\PolRefineInterval*{Q}{3}
+\PolRefineInterval*{Q}{4}
+\PolPrintIntervals{Q}
+% reports 1.05 &lt; Z_1 &lt; 1.06, 1.105 &lt; Z_2 &lt; 1.106, 1.1105 &lt; Z_3 &lt; 1.1106,
+% and 1.11105 &lt; Z_4 &lt; 1.11106.
+\PolEnsureIntervalLengths{Q}{-6}
+\PolPrintIntervals{Q}
+% of course finds here all roots exactly
+</pre>
+</div>
+<div class="section" id="the-degree-nine-polynomial-with-0-99-0-999-0-9999-as-triple-roots">
+<h2><a class="toc-backref" href="#id42">The degree nine polynomial with 0.99, 0.999, 0.9999 as triple roots</a></h2>
+<pre class="literal-block">
+% define a user command (xinttools is loaded automatically by polexpr)
+\newcommand\showmultiplicities[1]{% #1 = &quot;sturmname&quot;
+\xintFor* ##1 in {\xintSeq{1}{\PolSturmNbOfIsolatedZeros{#1}}}\do{%
+ The multiplicity is \PolSturmIsolatedZeroMultiplicity{#1}{##1}
+ \PolSturmIfZeroExactlyKnown{#1}{##1}%
+ {at the root $x=\PolSturmIsolatedZeroLeft{#1}{##1}$}
+ {for the root such that
+ $\PolSturmIsolatedZeroLeft{#1}{##1}&lt;x&lt;\PolSturmIsolatedZeroRight{#1}{##1}$}
+ \par
+}}%
+\PolDef{f}{(x-0.99)^3(x-0.999)^3(x-0.9999)^3}
+\renewcommand\PolTypesetOne[1]{\PolDecToString{\xintREZ{#1}}}
+\PolTypeset{f}\par
+\PolToSturm{f}{f}% it is allowed to use &quot;polname&quot; as &quot;sturmname&quot; too
+\PolSturmIsolateZerosAndGetMultiplicities{f}% use the &quot;sturmname&quot; here
+% or \PolSturmIsolateZeros*{f} which is exactly the same, but shorter..
+
+\showmultiplicities{f}
+</pre>
+<p>In this example, the output will look like this (but using math mode):</p>
+<pre class="literal-block">
+x^9 - 8.9667x^8 + 35.73400293x^7 - 83.070418400109x^6 + 124.143648875193123x^5
+- 123.683070924326075877x^4 + 82.149260397553075617891x^3
+- 35.07602992699900159127007x^2 + 8.7364078733314648368671733x
+- 0.967100824643585986488103299
+
+The multiplicity is 3 at the root x = 0.99
+The multiplicity is 3 at the root x = 0.999
+The multiplicity is 3 at the root x = 0.9999
+</pre>
+<p>On first pass, these rational roots were found (due to their relative
+magnitudes, using <tt class="docutils literal">\PolSturmIsolateZeros**</tt> was not needed here). But
+multiplicity computation works also with (decimal) roots not yet
+identified or with non-decimal or irrational roots.</p>
+<p>It is fun to modify only a tiny bit the polynomial and see if polexpr
+survives:</p>
+<pre class="literal-block">
+\PolDef{g}{f(x)+1e-27}
+\PolTypeset{g}\par
+\PolToSturm{g}{g}
+\PolSturmIsolateZeros*{g}
+
+\showmultiplicities{g}
+</pre>
+<p>This produces:</p>
+<pre class="literal-block">
+x^9 - 8.9667x^8 + 35.73400293x^7 - 83.070418400109x^6 + 124.143648875193123x^5
+- 123.683070924326075877x^4 + 82.149260397553075617891x^3
+- 35.07602992699900159127007x^2 + 8.7364078733314648368671733x
+- 0.967100824643585986488103298
+
+The multiplicity is 1 for the root such that 0.98 &lt; x &lt; 0.99
+The multiplicity is 1 for the root such that 0.9991 &lt; x &lt; 0.9992
+The multiplicity is 1 for the root such that 0.9997 &lt; x &lt; 0.9998
+</pre>
+<p>Which means that the multiplicity-3 roots each became a real and a pair of
+complex ones. Let's see them better:</p>
+<pre class="literal-block">
+\PolEnsureIntervalLengths{g}{-10}
+
+\showmultiplicities{g}
+</pre>
+<p>which produces:</p>
+<pre class="literal-block">
+The multiplicity is 1 for the root such that 0.9899888032 &lt; x &lt; 0.9899888033
+The multiplicity is 1 for the root such that 0.9991447980 &lt; x &lt; 0.9991447981
+The multiplicity is 1 for the root such that 0.9997663986 &lt; x &lt; 0.9997663987
+</pre>
+</div>
+<div class="section" id="a-degree-five-polynomial-with-three-rational-roots">
+<h2><a class="toc-backref" href="#id43">A degree five polynomial with three rational roots</a></h2>
+<pre class="literal-block">
+\poldef Q(x) := 1581755751184441 x^5
+ -14907697165025339 x^4
+ +48415668972339336 x^3
+ -63952057791306264 x^2
+ +46833913221154895 x
+ -49044360626280925;
+
+\PolToSturm{Q}{Q}
+%\begin{flushleft}
+ \renewcommand\PolTypesetCmdPrefix[1]{\allowbreak\xintiiifSgn{#1}{}{+}{+}}%
+ $Q_0(x) = \PolTypeset{Q_0}$
+%\end{flushleft}
+\PolSturmIsolateZeros**{Q}
+\PolPrintIntervals{Q}
+
+$Q_{norr}(x) = \PolTypeset{Q_norr}$
+</pre>
+<p>Here, all real roots are rational:</p>
+<pre class="literal-block">
+Z_1 = 833719/265381
+Z_2 = 165707065/52746197
+Z_3 = 355/113
+
+Q_norr(x) = x^2 + 1
+</pre>
+<p>And let's get their decimal expansion too:</p>
+<pre class="literal-block">
+% print decimal expansion of the found roots
+\renewcommand\PolPrintIntervalsPrintExactZero
+ {\xintTrunc{20}{\PolPrintIntervalsTheLeftEndPoint}\dots}
+\PolPrintIntervals{Q}
+
+Z_1 = 3.14159265358107777120...
+Z_2 = 3.14159265358979340254...
+Z_3 = 3.14159292035398230088...
+</pre>
+</div>
+<div class="section" id="a-mignotte-type-polynomial">
+<h2><a class="toc-backref" href="#id44">A Mignotte type polynomial</a></h2>
+<pre class="literal-block">
+\PolDef{P}{x^10 - (10x-1)^2}%
+\PolTypeset{P} % prints it in expanded form
+\PolToSturm{P}{P} % we can use same prefix for Sturm chain
+\PolSturmIsolateZeros{P} % finds 4 real roots
+This polynomial has \PolSturmNbOfIsolatedZeros{P} distinct real roots:
+\PolPrintIntervals{P}%
+% reports -2 &lt; Z_1 &lt; -1, 0.09 &lt; Z_2 &lt; 0.10, 0.1 &lt; Z_3 &lt; 0.2, 1 &lt; Z_4 &lt; 2
+Let us refine the second and third intervals to separate the corresponding
+roots:
+\PolRefineInterval*{P}{2}% will refine to 0.0999990 &lt; Z_2 &lt; 0.0999991
+\PolRefineInterval*{P}{3}% will refine to 0.100001 &lt; Z_3 &lt; 0.100002
+\PolPrintIntervals{P}%
+Let us now get to know all roots with 10 digits after decimal mark:
+\PolEnsureIntervalLengths{P}{-10}%
+\PolPrintIntervals{P}% now all roots are known 10 decimal digits after mark
+Finally, we display 20 digits of the second root:
+\PolEnsureIntervalLength{P}{2}{-20}% makes Z_2 known with 20 digits after mark
+\[\PolSturmIsolatedZeroLeft{P}{2}&lt;Z_2&lt;\PolSturmIsolatedZeroRight{P}{2}\]
+</pre>
+<p>The last line produces:</p>
+<pre class="literal-block">
+0.09999900004999650028 &lt; Z_2 &lt; 0.09999900004999650029
+</pre>
+</div>
+<div class="section" id="the-wilkinson-polynomial">
+<h2><a class="toc-backref" href="#id45">The Wilkinson polynomial</a></h2>
+<p>See <a class="reference external" href="https://en.wikipedia.org/wiki/Wilkinson%27s_polynomial">Wilkinson polynomial</a>.</p>
+<pre class="literal-block">
+\documentclass{article}
+\usepackage{polexpr}
+\begin{document}
+%\xintverbosetrue % for the curious...
+
+\poldef f(x) := mul((x - i), i = 1..20);
+
+\renewcommand\PolTypesetCmdPrefix[1]{\allowbreak\xintiiifSgn{#1}{}{+}{+}}%
+\renewcommand\PolTypesetOne[1]{\xintDecToString{#1}}%
+
+\noindent\PolTypeset{f}
+
+\PolToSturm{f}{f}
+\PolSturmIsolateZeros{f}
+\PolPrintIntervals{f}
+
+\clearpage
+
+\poldef g(x) := f(x) - 2**{-23} x**19;
+
+% be patient!
+\PolToSturm{g}{g}
+\noindent\PolTypeset{g_0}% integer coefficient primitive polynomial
+
+\PolSturmIsolateZeros{g}
+\PolEnsureIntervalLengths{g}{-10}
+
+\renewcommand\PolPrintIntervalsPrintMultiplicity{}
+\PolPrintIntervals*{g}
+
+\end{document}
+</pre>
+<p>The first polynomial:</p>
+<pre class="literal-block">
+f(x) = x**20
+- 210 x**19
++ 20615 x**18
+- 1256850 x**17
++ 53327946 x**16
+- 1672280820 x**15
++ 40171771630 x**14
+- 756111184500 x**13
++ 11310276995381 x**12
+- 135585182899530 x**11
++ 1307535010540395 x**10
+- 10142299865511450 x**9
++ 63030812099294896 x**8
+- 311333643161390640 x**7
++ 1206647803780373360 x**6
+- 3599979517947607200 x**5
++ 8037811822645051776 x**4
+- 12870931245150988800 x**3
++ 13803759753640704000 x**2
+- 8752948036761600000 x
++ 2432902008176640000
+</pre>
+<p>is handled fast enough (a few seconds), but the modified one <tt class="docutils literal">f(x) -
+<span class="pre">2**-23</span> <span class="pre">x**19</span></tt> takes about 20x longer (the Sturm chain polynomials
+have integer coefficients with up to 321 digits, whereas (surprisingly
+perhaps) those of the Sturm chain polynomials derived from <tt class="docutils literal">f</tt> never
+have more than 21 digits ...).</p>
+<p>Once the Sturm chain is computed and the zeros isolated, obtaining their
+decimal digits is relatively faster. Here is for the ten real roots of
+<tt class="docutils literal">f(x) - <span class="pre">2**-23</span> <span class="pre">x**19</span></tt> as computed by the code above:</p>
+<pre class="literal-block">
+Z_1 = 0.9999999999...
+Z_2 = 2.0000000000...
+Z_3 = 2.9999999999...
+Z_4 = 4.0000000002...
+Z_5 = 4.9999999275...
+Z_6 = 6.0000069439...
+Z_7 = 6.9996972339...
+Z_8 = 8.0072676034...
+Z_9 = 8.9172502485...
+Z_10 = 20.8469081014...
+</pre>
+</div>
+<div class="section" id="the-second-wilkinson-polynomial">
+<h2><a class="toc-backref" href="#id46">The second Wilkinson polynomial</a></h2>
+<pre class="literal-block">
+\documentclass{article}
+\usepackage{polexpr}
+\begin{document}
+\poldef f(x) := mul(x - 2^-i, i = 1..20);
+
+%\PolTypeset{f}
+
+\PolToSturm{f}{f}
+\PolSturmIsolateZeros**{f}
+\PolPrintIntervals{f}
+\end{document}
+</pre>
+<p>This takes more time than the polynomial with 1, 2, .., 20 as roots but
+less than the latter modified by the <tt class="docutils literal"><span class="pre">2**-23</span></tt> change in one
+coefficient.</p>
+<p>Here is the output (with release 0.7.2):</p>
+<pre class="literal-block">
+Z_1 = 0.00000095367431640625
+Z_2 = 0.0000019073486328125
+Z_3 = 0.000003814697265625
+Z_4 = 0.00000762939453125
+Z_5 = 0.0000152587890625
+Z_6 = 0.000030517578125
+Z_7 = 0.00006103515625
+Z_8 = 0.0001220703125
+Z_9 = 1/4096
+Z_10 = 1/2048
+Z_11 = 1/1024
+Z_12 = 1/512
+Z_13 = 1/256
+Z_14 = 1/128
+Z_15 = 0.015625
+Z_16 = 0.03125
+Z_17 = 0.0625
+Z_18 = 0.125
+Z_19 = 0.25
+Z_20 = 0.5
+</pre>
+<p>There is some incoherence in output format which has its source in the
+fact that some roots are found in branches which can only find decimal
+roots, whereas some are found in branches which could find general
+fractions and they use <tt class="docutils literal">\xintIrr</tt> before storage of the found root.
+This may evolve in future.</p>
+</div>
+<div class="section" id="the-degree-41-polynomial-with-2-1-9-1-8-0-0-1-1-9-2-as-roots">
+<h2><a class="toc-backref" href="#id47">The degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., 1.9, 2 as roots</a></h2>
+<pre class="literal-block">
+\PolDef{P}{mul((x-i*1e-1), i=-20..20)}% i/10 is same but less efficient
+</pre>
+<p>In the defining expression we could have used <tt class="docutils literal">i/10</tt> but this gives
+less efficient internal form for the coefficients (the <tt class="docutils literal">10</tt>'s end up
+in denominators). Using <tt class="docutils literal">\PolToExpr{P}</tt> after having done</p>
+<pre class="literal-block">
+\renewcommand\PolToExprCmd[1]{\PolDecToString{\xintREZ{#1}}}
+</pre>
+<p>we get this expanded form:</p>
+<pre class="literal-block">
+x^41
+-28.7*x^39
++375.7117*x^37
+-2975.11006*x^35
++15935.28150578*x^33
+-61167.527674162*x^31
++173944.259366417394*x^29
+-373686.963560544648*x^27
++613012.0665016658846445*x^25
+-771182.31133138163125495*x^23
++743263.86672885754888959569*x^21
+-545609.076599482896371978698*x^19
++301748.325708943677229642930528*x^17
+-123655.8987669450434698869844544*x^15
++36666.1782054884005855608205864192*x^13
+-7607.85821367459445649518380016128*x^11
++1053.15135918687298508885950223794176*x^9
+-90.6380005918141132650786081964032*x^7
++4.33701563847327366842552218288128*x^5
+-0.0944770968420804735498178265088*x^3
++0.00059190121813899276854174416896*x
+</pre>
+<p>which shows coefficients with up to 36 significant digits...</p>
+<p>Stress test: not a hard challenge to <tt class="docutils literal">xint + polexpr</tt>, but be a bit patient!</p>
+<pre class="literal-block">
+\PolDef{P}{mul((x-i*1e-1), i=-20..20)}%
+\PolToSturm{P}{S} % dutifully computes S_0, ..., S_{41}
+% the [1] optional argument limits the search to interval (-10,10)
+\PolSturmIsolateZeros[1]{S} % finds *exactly* (but a bit slowly) all 41 roots!
+\PolPrintIntervals{S} % nice, isn't it?
+</pre>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p>Release <tt class="docutils literal">0.5</tt> has <em>experimental</em> addition of optional argument
+<tt class="docutils literal">E</tt> to <tt class="docutils literal">\PolSturmIsolateZeros</tt>. It instructs to search roots only
+in interval <tt class="docutils literal"><span class="pre">(-10^E,</span> 10^E)</tt>. Important: the extremities are
+<em>assumed to not be roots</em>. In this example, the <tt class="docutils literal">[1]</tt> in
+<tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros[1]{S}</span></tt> gives some speed gain; without it, it
+turns out in this case that <tt class="docutils literal">polexpr</tt> would have started with
+<tt class="docutils literal"><span class="pre">(-10^6,</span> 10^6)</tt> interval.</p>
+<p class="last">Please note that this will probably get replaced in future by the
+specification of a general interval. Do not rely on meaning of this
+optional argument keeping the same.</p>
+</div>
+</div>
+<div class="section" id="roots-of-chebyshev-polynomials">
+<h2><a class="toc-backref" href="#id48">Roots of Chebyshev polynomials</a></h2>
+<pre class="literal-block">
+\newcount\mycount
+\poldef T_0(x) := 1;
+\poldef T_1(x) := x;
+\mycount 2
+\xintloop
+ \poldef T_\the\mycount(x) :=
+ 2x*T_\the\numexpr\mycount-1(x)
+ - T_\the\numexpr\mycount-2(x);
+\ifnum\mycount&lt;15
+\advance\mycount 1
+\repeat
+
+\[T_{15} = \PolTypeset[X]{T_15}\]
+\PolToSturm{T_15}{T_15}
+\PolSturmIsolateZeros{T_15}
+\PolEnsureIntervalLengths{T_15}{-10}
+\PolPrintIntervals{T_15}
+</pre>
+</div>
+</div>
+<div class="section" id="non-expandable-macros">
+<h1><a class="toc-backref" href="#id49">Non-expandable macros</a></h1>
+<div class="section" id="poldef-polname-letter-expression-in-letter">
+<span id="poldef"></span><h2><a class="toc-backref" href="#id50"><tt class="docutils literal">\poldef <span class="pre">polname(letter):=</span> expression in letter;</tt></a></h2>
+<blockquote>
+<p>This evaluates the <em>polynomial expression</em> and stores the coefficients
+in a private structure accessible later via other package macros,
+under the user-chosen <tt class="docutils literal">polname</tt>. Of course the <em>expression</em> can
+use other previously defined polynomials. Names must start with a
+letter and are constituted of letters, digits, underscores and
+(since <tt class="docutils literal">0.5.1</tt>) the right tick <tt class="docutils literal">'</tt>.
+The whole <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> syntax is authorized:</p>
+<pre class="literal-block">
+\poldef sin(z) := add((-1)^i z^(2i+1)/(2i+1)!, i = 0..10);
+</pre>
+<p>With fractional coefficients, beware the <a class="reference internal" href="#warningtacit">tacit multiplication issue</a>.</p>
+<p>As a side effect the function <tt class="docutils literal">polname()</tt> is recognized as a
+genuine <tt class="docutils literal"><span class="pre">\xintexpr...\relax</span></tt> function for (exact) numerical
+evaluation (or within an <tt class="docutils literal">\xintdefvar</tt> assignment.) It computes
+values not according to the original expression but via the Horner
+scheme corresponding to the polynomial coefficients.</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p>Release <tt class="docutils literal">0.3</tt> also did the necessary set-up to let the
+polynomial be known to the <tt class="docutils literal">\xintfloatexpr</tt> (or
+<tt class="docutils literal">\xintdeffloatvar</tt>) parser.</p>
+<p>Since <tt class="docutils literal">0.4</tt> this isn't done automatically. Even more, a
+previously existing floating point variant of the same name will
+be let undefined again, to avoid hard to debug mismatches between
+exact and floating point polynomials. This also applies when the
+polynomial is produced not via <tt class="docutils literal">\poldef</tt> or <tt class="docutils literal">\PolDef</tt> but as
+a product of the other package macros.</p>
+<p class="last">See <a class="reference internal" href="#polgenfloatvariant-polname">\PolGenFloatVariant{polname}</a>.</p>
+</div>
+<p>The original expression is lost after parsing, and in particular
+the package provides no way to typeset it. This has to be done
+manually, if needed.</p>
+</blockquote>
+</div>
+<div class="section" id="poldef-letter-polname-expression-in-letter">
+<span id="id2"></span><h2><a class="toc-backref" href="#id51"><tt class="docutils literal"><span class="pre">\PolDef[letter]{polname}{expression</span> in letter}</tt></a></h2>
+<blockquote>
+Does the same as <a class="reference external" href="poldef;">\poldef</a> in an undelimited macro
+format (thus avoiding potential problems with the catcode of the
+semi-colon in presence of some packages.) In absence of the
+<tt class="docutils literal">[letter]</tt> optional argument, the variable is assumed to be <tt class="docutils literal">x</tt>.</blockquote>
+</div>
+<div class="section" id="polgenfloatvariant-polname">
+<span id="polgenfloatvariant"></span><h2><a class="toc-backref" href="#id52"><tt class="docutils literal">\PolGenFloatVariant{polname}</tt></a></h2>
+<blockquote>
+<p>Makes the polynomial also usable in the <tt class="docutils literal">\xintfloatexpr</tt> parser.
+It will therein evaluates via an Horner scheme with coefficients
+already pre-rounded to the float precision.</p>
+<p>See also <a class="reference internal" href="#poltofloatexpr-polname">\PolToFloatExpr{polname}</a>.</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p>Release <tt class="docutils literal">0.3</tt> did this automatically on <tt class="docutils literal">\PolDef</tt> and
+<tt class="docutils literal">\poldef</tt> but this was removed at <tt class="docutils literal">0.4</tt> for optimization.</p>
+<p class="last">Any operation, for example generating the derivative polynomial,
+or dividing two polynomials or using the <tt class="docutils literal">\PolLet</tt>, <strong>must</strong> be
+followed by explicit usage of <tt class="docutils literal">\PolGenFloatVariant{polname}</tt> if
+the new polynomial is to be used in <tt class="docutils literal">\xintfloatexpr</tt> or alike
+context.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="pollet-polname-2-polname-1">
+<span id="pollet"></span><h2><a class="toc-backref" href="#id53"><tt class="docutils literal"><span class="pre">\PolLet{polname_2}={polname_1}</span></tt></a></h2>
+<blockquote>
+Makes a copy of the already defined polynomial <tt class="docutils literal">polname_1</tt> to a
+new one <tt class="docutils literal">polname_2</tt>. Same effect as
+<tt class="docutils literal"><span class="pre">\PolDef{polname_2}{polname_1(x)}</span></tt> but with less overhead. The
+<tt class="docutils literal">=</tt> is optional.</blockquote>
+</div>
+<div class="section" id="polgloballet-polname-2-polname-1">
+<span id="polgloballet"></span><h2><a class="toc-backref" href="#id54"><tt class="docutils literal"><span class="pre">\PolGlobalLet{polname_2}={polname_1}</span></tt></a></h2>
+<blockquote>
+Acts globally.</blockquote>
+</div>
+<div class="section" id="polassign-polname-toarray-macro">
+<span id="polassign"></span><h2><a class="toc-backref" href="#id55"><tt class="docutils literal"><span class="pre">\PolAssign{polname}\toarray\macro</span></tt></a></h2>
+<blockquote>
+<p>Defines a one-argument expandable macro <tt class="docutils literal"><span class="pre">\macro{#1}</span></tt> which expands
+to the (raw) #1th polynomial coefficient.</p>
+<ul class="simple">
+<li>Attention, coefficients here are indexed starting at 1.</li>
+<li>With #1=-1, -2, ..., <tt class="docutils literal"><span class="pre">\macro{#1}</span></tt> returns leading coefficients.</li>
+<li>With #1=0, returns the number of coefficients, i.e. <tt class="docutils literal">1 + deg f</tt>
+for non-zero polynomials.</li>
+<li>Out-of-range #1's return <tt class="docutils literal">0/1[0]</tt>.</li>
+</ul>
+<p>See also <a class="reference internal" href="#polnthcoeff-polname-number">\PolNthCoeff{polname}{number}</a>. The main difference is that
+with <tt class="docutils literal">\PolAssign</tt>, <tt class="docutils literal">\macro</tt> is made a prefix to <tt class="docutils literal">1 + deg f</tt>
+already defined (hidden to user) macros holding individually the
+coefficients but <a class="reference internal" href="#polnthcoeff-polname-number">\PolNthCoeff{polname}{number}</a> does each time the job
+to expandably recover the <tt class="docutils literal">Nth</tt> coefficient, and due to
+expandability can not store it in a macro for future usage (of course,
+it can be an argument in an <tt class="docutils literal">\edef</tt>.) The other difference
+is the shift by one in indexing, mentioned above (negative
+indices act the same in both.)</p>
+</blockquote>
+</div>
+<div class="section" id="polget-polname-fromarray-macro">
+<span id="polget"></span><h2><a class="toc-backref" href="#id56"><tt class="docutils literal"><span class="pre">\PolGet{polname}\fromarray\macro</span></tt></a></h2>
+<blockquote>
+<p>Does the converse operation to
+<tt class="docutils literal"><span class="pre">\PolAssign{polname}\toarray\macro</span></tt>. Each individual
+<tt class="docutils literal">\macro{number}</tt> gets expanded in an <tt class="docutils literal">\edef</tt> and then normalized
+via <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a>'s macro <tt class="docutils literal">\xintRaw</tt>.</p>
+<p>The leading zeros are removed from the polynomial.</p>
+<p>(contrived) Example:</p>
+<pre class="literal-block">
+\xintAssignArray{1}{-2}{5}{-3}\to\foo
+\PolGet{f}\fromarray\foo
+</pre>
+<p>This will define <tt class="docutils literal">f</tt> as would have <tt class="docutils literal">\poldef <span class="pre">f(x):=1-2x+5x^2-3x^3;</span></tt>.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">Prior to <tt class="docutils literal">0.5</tt>, coefficients were not normalized via
+<tt class="docutils literal">\xintRaw</tt> for internal storage.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polfromcsv-polname-csv">
+<span id="polfromcsv"></span><h2><a class="toc-backref" href="#id57"><tt class="docutils literal"><span class="pre">\PolFromCSV{polname}{&lt;csv&gt;}</span></tt></a></h2>
+<blockquote>
+<p>Defines a polynomial directly from the comma separated list of values
+(or a macro expanding to such a list) of its coefficients, the <em>first
+item</em> gives the constant term, the <em>last item</em> gives the leading
+coefficient, except if zero, then it is dropped (iteratively). List
+items are each expanded in an <tt class="docutils literal">\edef</tt> and then put into normalized
+form via <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a>'s macro <tt class="docutils literal">\xintRaw</tt>.</p>
+<p>As leading zero coefficients are removed:</p>
+<pre class="literal-block">
+\PolFromCSV{f}{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+</pre>
+<p>defines the zero polynomial, which holds only one coefficient.</p>
+<p>See also expandable macro <a class="reference internal" href="#poltocsv-polname">\PolToCSV</a>.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">Prior to <tt class="docutils literal">0.5</tt>, coefficients were not normalized via
+<tt class="docutils literal">\xintRaw</tt> for internal storage.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="poltypeset-polname">
+<span id="poltypeset"></span><h2><a class="toc-backref" href="#id58"><tt class="docutils literal">\PolTypeset{polname}</tt></a></h2>
+<blockquote>
+<p>Typesets in descending powers in math mode. It uses letter <tt class="docutils literal">x</tt> but
+this can be changed via an optional argument:</p>
+<pre class="literal-block">
+\PolTypeset[z]{polname}
+</pre>
+<p>By default zero coefficients are skipped (issue <tt class="docutils literal">\poltypesetalltrue</tt>
+to get all of them in output).</p>
+<p>These commands (whose meanings will be found in the package code)
+can be re-defined for customization. Their default definitions are
+expandable, but this is not a requirement.</p>
+</blockquote>
+<div class="section" id="poltypesetcmd-raw-coeff">
+<span id="poltypesetcmd"></span><h3><a class="toc-backref" href="#id59"><tt class="docutils literal">\PolTypesetCmd{raw_coeff}</tt></a></h3>
+<blockquote>
+<p>Checks if the coefficient is <tt class="docutils literal">1</tt> or <tt class="docutils literal"><span class="pre">-1</span></tt> and then skips printing
+the <tt class="docutils literal">1</tt>, except for the constant term. Also it sets conditional
+<a class="reference internal" href="#polifcoeffisplusorminusone-a-b">\PolIfCoeffIsPlusOrMinusOne{A}{B}</a>.</p>
+<p>The actual printing of the coefficients, when not equal to plus or
+minus one is handled by <a class="reference internal" href="#poltypesetone-raw-coeff">\PolTypesetOne{raw_coeff}</a>.</p>
+</blockquote>
+</div>
+<div class="section" id="poltypesetone-raw-coeff">
+<span id="poltypesetone"></span><h3><a class="toc-backref" href="#id60"><tt class="docutils literal">\PolTypesetOne{raw_coeff}</tt></a></h3>
+<blockquote>
+<p>The default is <tt class="docutils literal">\xintSignedFrac</tt> but this macro is annoying as it
+insists to use a power of ten, and not decimal notation.</p>
+<p>One can do things such as for example: <a class="footnote-reference" href="#id5" id="id4">[1]</a></p>
+<pre class="literal-block">
+\renewcommand\PolTypesetOne[1]{\num{\xintPFloat[5]{#1}}}
+\renewcommand\PolTypesetOne[1]{\num{\xintRound{4}{#1}}}
+</pre>
+<p>where e.g. we used the <tt class="docutils literal">\num</tt> macro of <tt class="docutils literal">siunitx</tt> as it
+understands floating point notation.</p>
+<table class="docutils footnote" frame="void" id="id5" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id4">[1]</a></td><td>the difference in the syntaxes of <tt class="docutils literal">\xintPFloat</tt> and
+<tt class="docutils literal">\xintRound</tt> is explained from the fact that
+<tt class="docutils literal">\xintPFloat</tt> by default uses the prevailing precision
+hence the extra argument like here <tt class="docutils literal">5</tt> is an optional one.</td></tr>
+</tbody>
+</table>
+<p>One can also give a try to using <a class="reference internal" href="#poldectostring-decimal-number">\PolDecToString{decimal number}</a>
+which uses decimal notation (at least for the numerator part).</p>
+</blockquote>
+</div>
+<div class="section" id="id6">
+<span id="poltypesetmonomialcmd"></span><h3><a class="toc-backref" href="#id61"><tt class="docutils literal">\PolTypesetMonomialCmd</tt></a></h3>
+<blockquote>
+This decides how a monomial (in variable <tt class="docutils literal">\PolVar</tt> and with
+exponent <tt class="docutils literal">\PolIndex</tt>) is to be printed. The default does nothing
+for the constant term, <tt class="docutils literal">\PolVar</tt> for the first degree and
+<tt class="docutils literal"><span class="pre">\PolVar^{\PolIndex}</span></tt> for higher degrees monomials. Beware that
+<tt class="docutils literal">\PolIndex</tt> expands to digit tokens and needs termination in
+<tt class="docutils literal">\ifnum</tt> tests.</blockquote>
+</div>
+<div class="section" id="poltypesetcmdprefix-raw-coeff">
+<span id="poltypesetcmdprefix"></span><h3><a class="toc-backref" href="#id62"><tt class="docutils literal">\PolTypesetCmdPrefix{raw_coeff}</tt></a></h3>
+<blockquote>
+Expands to a <tt class="docutils literal">+</tt> if the <tt class="docutils literal">raw_coeff</tt> is zero or positive, and to
+nothing if <tt class="docutils literal">raw_coeff</tt> is negative, as in latter case the
+<tt class="docutils literal">\xintSignedFrac</tt> used by <a class="reference internal" href="#poltypesetcmd-raw-coeff">\PolTypesetCmd{raw_coeff}</a> will put
+the <tt class="docutils literal">-</tt> sign in front of the fraction (if it is a fraction) and
+this will thus serve as separator in the typeset formula. Not used
+for the first term.</blockquote>
+</div>
+</div>
+<div class="section" id="id8">
+<span id="id7"></span><h2><a class="toc-backref" href="#id63"><tt class="docutils literal"><span class="pre">\PolTypeset*{polname}</span></tt></a></h2>
+<blockquote>
+Typesets in ascending powers. Use e.g. <tt class="docutils literal">[h]</tt> optional argument
+(after the <tt class="docutils literal">*</tt>) to use letter <tt class="docutils literal">h</tt> rather than <tt class="docutils literal">x</tt>.</blockquote>
+</div>
+<div class="section" id="poldiff-polname-1-polname-2">
+<span id="poldiff"></span><h2><a class="toc-backref" href="#id64"><tt class="docutils literal"><span class="pre">\PolDiff{polname_1}{polname_2}</span></tt></a></h2>
+<blockquote>
+<p>This sets <tt class="docutils literal">polname_2</tt> to the first derivative of <tt class="docutils literal">polname_1</tt>. It
+is allowed to issue <tt class="docutils literal"><span class="pre">\PolDiff{f}{f}</span></tt>, effectively replacing <tt class="docutils literal">f</tt>
+by <tt class="docutils literal">f'</tt>.</p>
+<p>Coefficients of the result <tt class="docutils literal">polname_2</tt> are irreducible fractions
+(see <a class="reference internal" href="#technicalities">Technicalities</a> for the whole story.)</p>
+</blockquote>
+</div>
+<div class="section" id="poldiff-n-polname-1-polname-2">
+<span id="poldiff-n"></span><h2><a class="toc-backref" href="#id65"><tt class="docutils literal"><span class="pre">\PolDiff[N]{polname_1}{polname_2}</span></tt></a></h2>
+<blockquote>
+This sets <tt class="docutils literal">polname_2</tt> to the <tt class="docutils literal">N</tt>-th derivative of <tt class="docutils literal">polname_1</tt>.
+Identical arguments is allowed. With <tt class="docutils literal">N=0</tt>, same effect as
+<tt class="docutils literal"><span class="pre">\PolLet{polname_2}={polname_1}</span></tt>. With negative <tt class="docutils literal">N</tt>, switches to
+using <tt class="docutils literal">\PolAntiDiff</tt>.</blockquote>
+</div>
+<div class="section" id="polantidiff-polname-1-polname-2">
+<span id="polantidiff"></span><h2><a class="toc-backref" href="#id66"><tt class="docutils literal"><span class="pre">\PolAntiDiff{polname_1}{polname_2}</span></tt></a></h2>
+<blockquote>
+<p>This sets <tt class="docutils literal">polname_2</tt> to the primitive of <tt class="docutils literal">polname_1</tt> vanishing
+at zero.</p>
+<p>Coefficients of the result <tt class="docutils literal">polname_2</tt> are irreducible fractions
+(see <a class="reference internal" href="#technicalities">Technicalities</a> for the whole story.)</p>
+</blockquote>
+</div>
+<div class="section" id="polantidiff-n-polname-1-polname-2">
+<span id="polantidiff-n"></span><h2><a class="toc-backref" href="#id67"><tt class="docutils literal"><span class="pre">\PolAntiDiff[N]{polname_1}{polname_2}</span></tt></a></h2>
+<blockquote>
+This sets <tt class="docutils literal">polname_2</tt> to the result of <tt class="docutils literal">N</tt> successive integrations on
+<tt class="docutils literal">polname_1</tt>. With negative <tt class="docutils literal">N</tt>, it switches to using <tt class="docutils literal">\PolDiff</tt>.</blockquote>
+</div>
+<div class="section" id="poldivide-polname-1-polname-2-polname-q-polname-r">
+<span id="poldivide"></span><h2><a class="toc-backref" href="#id68"><tt class="docutils literal"><span class="pre">\PolDivide{polname_1}{polname_2}{polname_Q}{polname_R}</span></tt></a></h2>
+<blockquote>
+This sets <tt class="docutils literal">polname_Q</tt> and <tt class="docutils literal">polname_R</tt> to be the quotient and
+remainder in the Euclidean division of <tt class="docutils literal">polname_1</tt> by
+<tt class="docutils literal">polname_2</tt>.</blockquote>
+</div>
+<div class="section" id="polquo-polname-1-polname-2-polname-q">
+<span id="polquo"></span><h2><a class="toc-backref" href="#id69"><tt class="docutils literal"><span class="pre">\PolQuo{polname_1}{polname_2}{polname_Q}</span></tt></a></h2>
+<blockquote>
+This sets <tt class="docutils literal">polname_Q</tt> to be the quotient in the Euclidean division
+of <tt class="docutils literal">polname_1</tt> by <tt class="docutils literal">polname_2</tt>.</blockquote>
+</div>
+<div class="section" id="polrem-polname-1-polname-2-polname-r">
+<span id="polrem"></span><h2><a class="toc-backref" href="#id70"><tt class="docutils literal"><span class="pre">\PolRem{polname_1}{polname_2}{polname_R}</span></tt></a></h2>
+<blockquote>
+This sets <tt class="docutils literal">polname_R</tt> to be the remainder in the Euclidean division
+of <tt class="docutils literal">polname_1</tt> by <tt class="docutils literal">polname_2</tt>.</blockquote>
+</div>
+<div class="section" id="polgcd-polname-1-polname-2-polname-gcd">
+<span id="polgcd"></span><h2><a class="toc-backref" href="#id71"><tt class="docutils literal"><span class="pre">\PolGCD{polname_1}{polname_2}{polname_GCD}</span></tt></a></h2>
+<blockquote>
+This sets <tt class="docutils literal">polname_GCD</tt> to be the (monic) GCD of the two first
+polynomials. It is a unitary polynomial except if both <tt class="docutils literal">polname_1</tt>
+and <tt class="docutils literal">polname_2</tt> vanish, then <tt class="docutils literal">polname_GCD</tt> is the zero
+polynomial.</blockquote>
+<!-- ``\PolIGCD{polname_1}{polname_2}{polname_iGCD}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ **NOT YET**
+
+ This **assumes** that the two polynomials have integer coefficients.
+ It then computes the greatest common divisor in the integer
+ polynomial ring, normalized to have a positive leading coefficient
+ (if the inputs are not both zero).
+
+``\PolIContent{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ **NOT YET**
+
+ This computes a positive rational number such that dividing the
+ polynomial with it returns an integer coefficients polynomial with
+ no common factor among the coefficients. -->
+</div>
+<div class="section" id="poltosturm-polname-sturmname">
+<span id="poltosturm"></span><h2><a class="toc-backref" href="#id72"><tt class="docutils literal"><span class="pre">\PolToSturm{polname}{sturmname}</span></tt></a></h2>
+<blockquote>
+<p>With <tt class="docutils literal">polname</tt> being for example <tt class="docutils literal">P</tt>, the macro starts by
+computing polynomials <tt class="docutils literal">P</tt> and <tt class="docutils literal">P'</tt>, then computes the (opposite
+of the) remainder in euclidean division, iteratively.</p>
+<p>The last non-zero remainder <tt class="docutils literal">P_N_</tt> (where <tt class="docutils literal">N</tt> is obtainable as
+<a class="reference internal" href="#polsturmchainlength-sturmname">\PolSturmChainLength{sturmname}</a>) is up to a factor
+the GCD of <tt class="docutils literal">P</tt> and <tt class="docutils literal">P'</tt> hence it is a constant if and only if
+<tt class="docutils literal">P</tt> is square-free.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<ul class="last simple">
+<li>Since <tt class="docutils literal">0.5</tt> all these polynomials are divided by their rational
+content, so they have integer coefficients with no common factor,
+and the last one if a constant is either <tt class="docutils literal">1</tt> or <tt class="docutils literal"><span class="pre">-1</span></tt>.</li>
+<li>After this normalization to primitive polynomials, they are
+stored internally as <tt class="docutils literal">sturmname_k_</tt>, <tt class="docutils literal">k=0,1, ...</tt>.</li>
+<li>These polynomials are used internally only. To keep them as
+genuine declared polynomials also after the macro call, use the
+starred variant <a class="reference internal" href="#id9">PolToSturm*</a>.</li>
+</ul>
+</div>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">It is perfectly allowed to use the polynomial name as Sturm chain name:
+<tt class="docutils literal"><span class="pre">\PolToSturm{f}(f}</span></tt>.</p>
+</div>
+<p>The macro then declares <tt class="docutils literal">sturmname_0</tt>, <tt class="docutils literal">sturmname_1</tt>, ..., which are
+the (non-declared) <tt class="docutils literal">sturmname_k_</tt> divided by the last one. Division is
+not done if this last one is the constant <tt class="docutils literal">1</tt> or <tt class="docutils literal"><span class="pre">-1</span></tt>, i.e. if the
+original polynomial was square-free. These polynomials are primitive
+polynomials too, i.e. with integer coefficients having no common factor.</p>
+<p>Thus <tt class="docutils literal">sturmname_0</tt> has exactly the same real and complex roots as
+polynomial <tt class="docutils literal">polname</tt>, but with each root now of multiplicity one:
+i.e. it is the &quot;square-free part&quot; of original polynomial <tt class="docutils literal">polname</tt>.</p>
+<p>Notice that <tt class="docutils literal">sturmname_1</tt> isn't necessarily the derivative of
+<tt class="docutils literal">sturmname_0</tt> due to the various normalizations.</p>
+<p>The polynomials <tt class="docutils literal">sturmname_k</tt> main utility is for the execution of
+<a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a>. Be careful not to use these
+names <tt class="docutils literal">sturmname_0</tt>, <tt class="docutils literal">sturmname_1</tt>, etc... for defining other
+polynomials after having done <tt class="docutils literal"><span class="pre">\PolToSturm{polname}{sturmname}</span></tt> and
+before executing <tt class="docutils literal">\PolSturmIsolateZeros{sturmname}</tt> else the
+latter will behave erroneously.</p>
+<p><a class="reference internal" href="#polsturmchainlength-sturmname">\PolSturmChainLength{sturmname}</a> gives the index of the last
+element of the Sturm chain.</p>
+</blockquote>
+</div>
+<div class="section" id="id10">
+<span id="id9"></span><h2><a class="toc-backref" href="#id73"><tt class="docutils literal"><span class="pre">\PolToSturm*{polname}{sturmname}</span></tt></a></h2>
+<blockquote>
+<p>Does the same as <a class="reference internal" href="#poltosturm">un-starred version</a> and additionally it
+keeps for user usage the memory of the <em>un-normalized</em> Sturm chain
+polynomials <tt class="docutils literal">sturmname_k_</tt>, <tt class="docutils literal">k=0,1, <span class="pre">...,</span> N</tt>, with
+<tt class="docutils literal">N</tt> being <a class="reference internal" href="#polsturmchainlength-sturmname">\PolSturmChainLength{sturmname}</a>.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">This behaviour was modified at <tt class="docutils literal">0.6</tt>, anyhow the macro was
+broken at <tt class="docutils literal">0.5</tt>.</p>
+</div>
+<div class="admonition hint">
+<p class="first admonition-title">Hint</p>
+<p class="last">The square-free part of <tt class="docutils literal">polname</tt> is <tt class="docutils literal">sturmname_0</tt>, and their
+quotient is the polynomial with name
+<tt class="docutils literal">sturname_\PolSturmChainLength{sturmname}_</tt>. It thus easy to
+set-up a loop iteratively computing the latter until the last one
+is a constant, thus obtaining the decomposition of an <tt class="docutils literal">f</tt> as
+a product <tt class="docutils literal">c f_1 f_2 f_3 ...</tt> of a constant and square-free (primitive)
+polynomials, where each <tt class="docutils literal">f_i</tt> divides its predecessor.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polsettosturmchainsignchangesat-macro-sturmname-fraction">
+<span id="polsettosturmchainsignchangesat"></span><h2><a class="toc-backref" href="#id74"><tt class="docutils literal"><span class="pre">\PolSetToSturmChainSignChangesAt{\macro}{sturmname}{fraction}</span></tt></a></h2>
+<blockquote>
+<p>Sets macro <tt class="docutils literal">\macro</tt> to the number of sign changes in the Sturm
+chain with name prefix <tt class="docutils literal">sturmname</tt>, at location <tt class="docutils literal">fraction</tt>
+(which must be in format as acceptable by the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros.)</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p>The author was lazy and did not provide rather an expandable
+variant, where one would do <tt class="docutils literal"><span class="pre">\edef\macro{\PolNbOf...}</span></tt>.</p>
+<p>This will presumably get added in a future release.</p>
+<p class="last">After some hesitation it was decided the macro would by default
+act globally. To make the scope of its macro definition local,
+use <tt class="docutils literal">[\empty]</tt> as extra optional argument.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polsettonbofzeroswithin-macro-sturmname-value-a-value-b">
+<span id="polsettonbofzeroswithin"></span><h2><a class="toc-backref" href="#id75"><tt class="docutils literal"><span class="pre">\PolSetToNbOfZerosWithin{\macro}{sturmname}{value_a}{value_b}</span></tt></a></h2>
+<blockquote>
+<p>Applies the <a class="reference external" href="https://en.wikipedia.org/wiki/Sturm%27s_theorem">Sturm Theorem</a> to set <tt class="docutils literal">\macro</tt> to the exact number
+of <strong>distinct</strong> roots of <tt class="docutils literal">sturmname_0</tt> in the interval <tt class="docutils literal">(value_a,
+value_b]</tt> (the macro first re-orders the value for <tt class="docutils literal">value_a &lt;=
+value_b</tt> to hold).</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p>The author was lazy and did not provide rather an expandable
+variant, where one would do <tt class="docutils literal"><span class="pre">\edef\macro{\PolNbOf...}</span></tt>.</p>
+<p>This will presumably get added in future.</p>
+<p class="last">After some hesitation it was decided the macro would by default
+act globally. To make the scope of its macro definition local,
+use <tt class="docutils literal">[\empty]</tt> as extra optional argument.</p>
+</div>
+<p>See also the expandable
+<a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequalto-value">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}</a>, from
+which it is immediate (with <tt class="docutils literal">\numexpr</tt>) to create an expandable
+variant of this macro. However the difference is that this macro
+requires only <a class="reference internal" href="#poltosturm">\PolToSturm</a> to have been executed,
+whereas the expandable variant requires prior execution of
+<a class="reference internal" href="#polsturmisolatezeros">\PolSturmIsolateZeros</a>.</p>
+<p>See also the expandable
+<a class="reference internal" href="#polsturmnbwithmultofrootsof-sturmname-lessthanorequalto-value">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualTo{value}</a>
+which requires prior execution of
+<a class="reference internal" href="#id11">\PolSturmIsolateZeros*</a>.</p>
+</blockquote>
+</div>
+<div class="section" id="polsturmisolatezeros-sturmname">
+<span id="polsturmisolatezeros"></span><h2><a class="toc-backref" href="#id76"><tt class="docutils literal">\PolSturmIsolateZeros{sturmname}</tt></a></h2>
+<blockquote>
+<p>The macros locates, using <a class="reference external" href="https://en.wikipedia.org/wiki/Sturm%27s_theorem">Sturm theorem</a>, as many disjoint
+intervals as there are (real) roots.</p>
+<div class="admonition important">
+<p class="first admonition-title">Important</p>
+<p>The Sturm chain must have been produced by an earlier
+<a class="reference internal" href="#poltosturm-polname-sturmname">\PolToSturm{polname}{sturmname}</a>.</p>
+<p>Why does this macro ask for argument the name of Sturm chain,
+rather than the name of a polynomial? well this is mainly for
+legacy reason, and because it is accompanied by other macros for
+which it is simpler to assume the argument will be the name of an
+already computed Sturm chain.</p>
+<p>Notice that <tt class="docutils literal"><span class="pre">\PolToSturm{f}{f}</span></tt> is perfectly legal (the
+<tt class="docutils literal">sturmname</tt> can be same as the <tt class="docutils literal">polname</tt>): it defines
+polynomials <tt class="docutils literal">f_0</tt>, <tt class="docutils literal">f_1</tt>, ... having <tt class="docutils literal">f</tt> has name prefix.</p>
+<p class="last">Such a prior call
+to <tt class="docutils literal">\PolToSturm</tt> must have been made at any rate for
+<tt class="docutils literal">\PolSturmIsolateZeros</tt> to be usable.</p>
+</div>
+<p>After its execution they are two types of such intervals (stored in
+memory and accessible via macros or <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> variables, see below):</p>
+<ul class="simple">
+<li>singleton <tt class="docutils literal">{a}</tt>: then <tt class="docutils literal">a</tt> is a root, (necessarily a decimal
+number, but not all such decimal numbers are exactly identified yet).</li>
+<li>open intervals <tt class="docutils literal">(a,b)</tt>: then there is exactly one root <tt class="docutils literal">z</tt>
+such that <tt class="docutils literal">a &lt; z &lt; b</tt>, and the end points are guaranteed to not
+be roots.</li>
+</ul>
+<p>The interval boundaries are decimal numbers, originating
+in iterated decimal subdivision from initial intervals
+<tt class="docutils literal"><span class="pre">(-10^E,</span> 0)</tt> and <tt class="docutils literal">(0, 10^E)</tt> with <tt class="docutils literal">E</tt> chosen initially large
+enough so that all roots are enclosed; if zero is a root it is always
+identified as such. The non-singleton intervals are of the
+type <tt class="docutils literal">(a/10^f, <span class="pre">(a+1)/10^f)</span></tt> with <tt class="docutils literal">a</tt> an integer, which is
+neither <tt class="docutils literal">0</tt> nor <tt class="docutils literal"><span class="pre">-1</span></tt>. Hence either <tt class="docutils literal">a</tt> and <tt class="docutils literal">a+1</tt> are both positive
+or they are both negative.</p>
+<p>One does not <em>a priori</em> know what will be the lengths of these
+intervals (except that they are always powers of ten), they
+vary depending on how many digits two successive roots have in
+common in their respective decimal expansions.</p>
+<div class="admonition important">
+<p class="first admonition-title">Important</p>
+<p>If some two consecutive intervals share an end-point, no
+information is yet gained about the separation between the two
+roots which could at this stage be arbitrarily small.</p>
+<p class="last">See <a class="reference internal" href="#polrefineinterval-sturmname-index">\PolRefineInterval*{sturmname}{index}</a> which addresses
+this issue.</p>
+</div>
+<!-- This procedure is covariant
+with the independent variable ``x`` becoming ``-x``.
+Hmm, pas sûr et trop fatigué -->
+<p>The interval boundaries (and exactly found roots) are made available
+for future computations in <tt class="docutils literal">\xintexpr</tt>-essions or polynomial
+definitions as variables <tt class="docutils literal">&lt;sturmname&gt;L_1</tt>,
+<tt class="docutils literal">&lt;sturmname&gt;L_2</tt>, etc..., for the left end-points and
+<tt class="docutils literal">&lt;sturmname&gt;R_1</tt>, <tt class="docutils literal">&lt;sturmname&gt;R_2</tt>, ..., for the right
+end-points.</p>
+<p>Thus for example, if <tt class="docutils literal">sturmname</tt> is <tt class="docutils literal">f</tt>, one can use the
+<a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> variables <tt class="docutils literal">fL_1</tt>, <tt class="docutils literal">fL_2</tt>, ... to refer in expressions
+to the left end-points (or to the exact root, if left and right end
+points coincide). Additionally, <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> variable <tt class="docutils literal">fZ_1_isknown</tt>
+will have value <tt class="docutils literal">1</tt> if the root in the first interval is known,
+and <tt class="docutils literal">0</tt> otherwise. And similarly for the other intervals.</p>
+<p>Also, macros <a class="reference internal" href="#polsturmisolatedzeroleft-sturmname-index">\PolSturmIsolatedZeroLeft{sturmname}{index}</a> and
+<a class="reference internal" href="#polsturmisolatedzeroright-sturmname-index">\PolSturmIsolatedZeroRight{sturmname}{index}</a> are provided which
+expand to these same values, written in decimal notation (i.e.
+pre-processed by <a class="reference internal" href="#poldectostring">\PolDecToString</a>.) And there
+is also <a class="reference internal" href="#polsturmifzeroexactlyknown-sturmname-index-a-b">\PolSturmIfZeroExactlyKnown{sturmname}{index}{A}{B}</a>.</p>
+<div class="admonition important">
+<p class="first admonition-title">Important</p>
+<p class="last">Trailing zeroes in the stored decimal numbers accessible via the
+macros are significant: they are also present in the decimal
+expansion of the exact root.</p>
+</div>
+<p>These variables and macros are automatically updated when one next
+uses macros such as <a class="reference internal" href="#polrefineinterval-sturmname-index">\PolRefineInterval*{sturmname}{index}</a>.</p>
+<p>The start of decimal expansion of a positive <tt class="docutils literal">k</tt>-th root is given
+by <a class="reference internal" href="#polsturmisolatedzeroleft">\PolSturmIsolatedZeroLeft{sturmname}{k}</a>, and for a negative root it is given
+by <a class="reference internal" href="#polsturmisolatedzeroright">PolSturmIsolatedZeroRight{sturmname}{k}</a>. These two decimal
+numbers are either both zero or both of the same sign.</p>
+<p>The number of distinct roots is obtainable expandably as
+<a class="reference internal" href="#polsturmnbofisolatedzeros-sturmname">\PolSturmNbOfIsolatedZeros{sturmname}</a>.</p>
+<p>Furthermore
+<a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequalto-value">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}</a> and
+<a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequaltoexpr-expression">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</a>.
+will expandably compute respectively the number of real roots at
+most equal to <tt class="docutils literal">value</tt> or <tt class="docutils literal">expression</tt>, and the same but with
+multiplicities.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">In the current implementation the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> variables
+and <a class="reference external" href="http://www.ctan.org/pkg/xint">xinttools</a> arrays are globally defined. On the
+other hand the Sturm sequence polynomials obey the current scope.</p>
+</div>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p>As all computations are done <em>exactly</em> there can be no errors...
+apart those due to bad coding by author. The results are exact
+bounds for the mathematically exact real roots.</p>
+<p class="last">Future releases will perhaps also provide macros based on Newton
+or Regula Falsi methods. Exact computations with such methods
+lead however quickly to very big fractions, and this forces usage
+of some rounding scheme for the abscissas if computation times
+are to remain reasonable. This raises issues of its own, which
+are studied in numerical mathematics.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="id12">
+<span id="id11"></span><h2><a class="toc-backref" href="#id77"><tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros*{sturmname}</span></tt></a></h2>
+<blockquote>
+<p>The macro does the same as <a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a> and
+then in addition it does the extra work to determine all
+multiplicities (of the real roots):
+after executing this macro,
+<a class="reference internal" href="#polsturmisolatedzeromultiplicity-sturmname-index">\PolSturmIsolatedZeroMultiplicity{sturmname}{index}</a> will expand
+to the multiplicity of the root located in the <tt class="docutils literal">index</tt>-th
+interval (intervals are enumerated from left to right, with index
+starting at <tt class="docutils literal">1</tt>).</p>
+<p>Furthermore, if for example the <tt class="docutils literal">sturmname</tt> is <tt class="docutils literal">f</tt>, <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a>
+variables <tt class="docutils literal">fM_1</tt>, <tt class="docutils literal">fM_2</tt>... hold the multiplicities thus
+computed.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">It is <strong>not</strong> necessary to have executed the <a class="reference internal" href="#id9">PolToSturm*</a> starred
+variant, as the non-starred variant keeps internally the memory of the
+original GCD (and even of the full non-normalized original Sturm
+chain), even though it does not make the declarations as <em>user-level</em>
+genuine polynomials.</p>
+</div>
+<p>See <a class="reference internal" href="#the-degree-nine-polynomial-with-0-99-0-999-0-9999-as-triple-roots">The degree nine polynomial with 0.99, 0.999, 0.9999 as triple
+roots</a> for an example.</p>
+</blockquote>
+</div>
+<div class="section" id="id14">
+<span id="id13"></span><h2><a class="toc-backref" href="#id78"><tt class="docutils literal"><span class="pre">\PolSturmIsolateZeros**{sturmname}</span></tt></a></h2>
+<blockquote>
+<p>The macro does the same as <a class="reference internal" href="#id12">\PolSturmIsolateZeros*{sturmname}</a> and
+in addition it does the extra work to determine all the <em>rational</em>
+roots.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">After execution of this macro, a root is &quot;known&quot; if and only if
+it is rational.</p>
+</div>
+<p>Furthermore, primitive polynomial <tt class="docutils literal">sturmname_sqf_norr</tt> is created
+to match the (square-free) <tt class="docutils literal">sturmname_0</tt> from which all rational
+roots have been removed (see <a class="reference internal" href="#polexprsetup">\polexprsetup</a> for customizing this
+name). The number of distinct rational roots is thus the difference
+between the degrees of these two polynomials (see also
+<a class="reference internal" href="#polsturmnbofrationalroots-sturmname">\PolSturmNbOfRationalRoots{sturmname}</a>).</p>
+<p>And <tt class="docutils literal">sturmname_norr</tt> is <tt class="docutils literal">sturmname_0_</tt> from which all rational
+roots have been removed (see <a class="reference internal" href="#polexprsetup">\polexprsetup</a>), i.e. it contains
+the irrational roots of the original polynomial, with the same
+multiplicities.</p>
+<p>See <a class="reference internal" href="#a-degree-five-polynomial-with-three-rational-roots">A degree five polynomial with three rational
+roots</a> for an example.</p>
+</blockquote>
+</div>
+<div class="section" id="polsturmisolatezerosandgetmultiplicities-sturmname">
+<span id="polsturmisolatezerosandgetmultiplicities"></span><h2><a class="toc-backref" href="#id79"><tt class="docutils literal">\PolSturmIsolateZerosAndGetMultiplicities{sturmname}</tt></a></h2>
+<blockquote>
+This is another name for <a class="reference internal" href="#id12">\PolSturmIsolateZeros*{sturmname}</a>.</blockquote>
+</div>
+<div class="section" id="polsturmisolatezerosgetmultiplicitiesandrationalroots-sturmname">
+<span id="polsturmisolatezerosgetmultiplicitiesandrationalroots"></span><h2><a class="toc-backref" href="#id80"><tt class="docutils literal">\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{sturmname}</tt></a></h2>
+<blockquote>
+This is another name for <a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a>.</blockquote>
+</div>
+<div class="section" id="polsturmisolatezerosandfindrationalroots-sturmname">
+<h2><a class="toc-backref" href="#id81"><tt class="docutils literal">\PolSturmIsolateZerosAndFindRationalRoots{sturmname}</tt></a></h2>
+<blockquote>
+<p>This works exactly like <a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a>
+(inclusive of declaring the polynomials <tt class="docutils literal">sturmname_sqf_norr</tt> and
+<tt class="docutils literal">sturmname_norr</tt> with no rational roots) except that it does <em>not</em>
+compute the multiplicities of the <em>non-rational</em> roots.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">There is no macro to find the rational roots but not compute
+their multiplicities at the same time.</p>
+</div>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p>This macro does <em>not</em> define <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> variables
+<tt class="docutils literal">sturmnameM_1</tt>, <tt class="docutils literal">sturmnameM_2</tt>, ... holding the
+multiplicities and it leaves the multiplicity array (whose accessor
+is <a class="reference internal" href="#polsturmisolatedzeromultiplicity-sturmname-index">\PolSturmIsolatedZeroMultiplicity{sturmname}{index}</a>) into
+a broken state, as all non-rational roots will supposedly have
+multiplicity one. This means that the output of
+<a class="reference internal" href="#id18">\PolPrintIntervals*</a> for example will be
+erroneous for the intervals with irrational roots.</p>
+<p class="last">I decided to document it because finding multiplicities of the
+non rational roots is somewhat costly, and one may be interested
+only into finding the rational roots (of course random
+polynomials with integer coefficients will not have <em>any</em>
+rational root anyhow).</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polrefineinterval-sturmname-index">
+<span id="polrefineinterval"></span><h2><a class="toc-backref" href="#id82"><tt class="docutils literal"><span class="pre">\PolRefineInterval*{sturmname}{index}</span></tt></a></h2>
+<blockquote>
+The <tt class="docutils literal">index</tt>-th interval (starting indexing at one) is further
+subdivided as many times as is necessary in order for the newer
+interval to have both its end-points distinct from the end-points of
+the original interval. This means that the <tt class="docutils literal">k</tt>th root is then
+strictly separated from the other roots.</blockquote>
+</div>
+<div class="section" id="polrefineinterval-n-sturmname-index">
+<span id="polrefineinterval-n"></span><h2><a class="toc-backref" href="#id83"><tt class="docutils literal"><span class="pre">\PolRefineInterval[N]{sturmname}{index}</span></tt></a></h2>
+<blockquote>
+The <tt class="docutils literal">index</tt>-th interval (starting count at one) is further
+subdivided once, reducing its length by a factor of 10. This is done
+<tt class="docutils literal">N</tt> times if the optional argument <tt class="docutils literal">[N]</tt> is present.</blockquote>
+</div>
+<div class="section" id="polensureintervallength-sturmname-index-e">
+<span id="polensureintervallength"></span><h2><a class="toc-backref" href="#id84"><tt class="docutils literal"><span class="pre">\PolEnsureIntervalLength{sturmname}{index}{E}</span></tt></a></h2>
+<blockquote>
+The <tt class="docutils literal">index</tt>-th interval is subdivided until its length becomes at
+most <tt class="docutils literal">10^E</tt>. This means (for <tt class="docutils literal">E&lt;0</tt>) that the first <tt class="docutils literal"><span class="pre">-E</span></tt> digits
+after decimal mark of the <tt class="docutils literal">k</tt>th root will then be known exactly.</blockquote>
+</div>
+<div class="section" id="polensureintervallengths-sturmname-e">
+<span id="polensureintervallengths"></span><h2><a class="toc-backref" href="#id85"><tt class="docutils literal"><span class="pre">\PolEnsureIntervalLengths{sturmname}{E}</span></tt></a></h2>
+<blockquote>
+<p>The intervals as obtained from <tt class="docutils literal">\PolSturmIsolateZeros</tt> are (if
+necessary) subdivided further by (base 10) dichotomy in order for
+each of them to have length at most <tt class="docutils literal">10^E</tt> (length will be shorter
+than <tt class="docutils literal">10^E</tt> in output only if it did not change or became zero.)</p>
+<p>This means that decimal expansions of all roots will be known with
+<tt class="docutils literal"><span class="pre">-E</span></tt> digits (for <tt class="docutils literal">E&lt;0</tt>) after decimal mark.</p>
+</blockquote>
+</div>
+<div class="section" id="polprintintervals-varname-sturmname">
+<span id="polprintintervals"></span><h2><a class="toc-backref" href="#id86"><tt class="docutils literal"><span class="pre">\PolPrintIntervals[varname]{sturmname}</span></tt></a></h2>
+<blockquote>
+<p>This is a convenience macro which prints the bounds for the roots
+<tt class="docutils literal">Z_1</tt>, <tt class="docutils literal">Z_2</tt>, ... (the optional argument <tt class="docutils literal">varname</tt> allows to
+specify a replacement for the default <tt class="docutils literal">Z</tt>). This will be done (by
+default) in a
+math mode <tt class="docutils literal">array</tt>, one interval per row, and pattern <tt class="docutils literal">rcccl</tt>,
+where the second and fourth column hold the <tt class="docutils literal">&lt;</tt> sign, except when
+the interval reduces to a singleton, which means the root is known
+exactly.</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last">This macro was refactored at 0.7, its default output remained
+identical but the ways to customize it got completely
+modified.</p>
+</div>
+<p>See next macros which govern its output.</p>
+</blockquote>
+<div class="section" id="polprintintervalsnorealroots">
+<h3><a class="toc-backref" href="#id87"><tt class="docutils literal">\PolPrintIntervalsNoRealRoots</tt></a></h3>
+<blockquote>
+<p>Executed in place of an <tt class="docutils literal">array</tt> environment, when there are no
+real roots. Default definition:</p>
+<pre class="literal-block">
+\newcommand\PolPrintIntervalsNoRealRoots{}
+</pre>
+</blockquote>
+</div>
+<div class="section" id="polprintintervalsbeginenv">
+<h3><a class="toc-backref" href="#id88"><tt class="docutils literal">\PolPrintIntervalsBeginEnv</tt></a></h3>
+<blockquote>
+<p>Default definition:</p>
+<pre class="literal-block">
+\newcommand\PolPrintIntervalsBeginEnv{\[\begin{array}{rcccl}}
+</pre>
+</blockquote>
+</div>
+<div class="section" id="polprintintervalsendenv">
+<h3><a class="toc-backref" href="#id89"><tt class="docutils literal">\PolPrintIntervalsEndEnv</tt></a></h3>
+<blockquote>
+<p>Default definition:</p>
+<pre class="literal-block">
+\newcommand\PolPrintIntervalsEndEnv{\end{array}\]}
+</pre>
+</blockquote>
+</div>
+<div class="section" id="polprintintervalsknownroot">
+<h3><a class="toc-backref" href="#id90"><tt class="docutils literal">\PolPrintIntervalsKnownRoot</tt></a></h3>
+<blockquote>
+<p>Default definition:</p>
+<pre class="literal-block">
+\newcommand\PolPrintIntervalsKnownRoot{%
+ &amp;&amp;\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}%
+ &amp;=&amp;\PolPrintIntervalsPrintExactZero
+}
+</pre>
+</blockquote>
+</div>
+<div class="section" id="polprintintervalsunknownroot">
+<h3><a class="toc-backref" href="#id91"><tt class="docutils literal">\PolPrintIntervalsUnknownRoot</tt></a></h3>
+<blockquote>
+<p>Default definition:</p>
+<pre class="literal-block">
+\newcommand\PolPrintIntervalsUnknownRoot{%
+ \PolPrintIntervalsPrintLeftEndPoint&amp;&lt;&amp;%
+ \PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}&amp;&lt;&amp;%
+ \PolPrintIntervalsPrintRightEndPoint
+}
+</pre>
+</blockquote>
+</div>
+<div class="section" id="id15">
+<span id="polprintintervalsprintexactzero"></span><h3><a class="toc-backref" href="#id92"><tt class="docutils literal">\PolPrintIntervalsPrintExactZero</tt></a></h3>
+<blockquote>
+<p>Default definition:</p>
+<pre class="literal-block">
+\newcommand\PolPrintIntervalsPrintExactZero{\PolPrintIntervalsTheLeftEndPoint}
+</pre>
+</blockquote>
+</div>
+<div class="section" id="id16">
+<span id="polprintintervalsprintleftendpoint"></span><h3><a class="toc-backref" href="#id93"><tt class="docutils literal">\PolPrintIntervalsPrintLeftEndPoint</tt></a></h3>
+<blockquote>
+<p>Default definition:</p>
+<pre class="literal-block">
+\newcommand\PolPrintIntervalsPrintLeftEndPoint{\PolPrintIntervalsTheLeftEndPoint}
+</pre>
+</blockquote>
+</div>
+<div class="section" id="id17">
+<span id="polprintintervalsprintrightendpoint"></span><h3><a class="toc-backref" href="#id94"><tt class="docutils literal">\PolPrintIntervalsPrintRightEndPoint</tt></a></h3>
+<blockquote>
+<p>Default definition is:</p>
+<pre class="literal-block">
+\newcommand\PolPrintIntervalsPrintRightEndPoint{\PolPrintIntervalsTheRightEndPoint}
+</pre>
+</blockquote>
+</div>
+</div>
+<div class="section" id="id19">
+<span id="id18"></span><h2><a class="toc-backref" href="#id95"><tt class="docutils literal"><span class="pre">\PolPrintIntervals*[varname]{sturmname}</span></tt></a></h2>
+<blockquote>
+<p>This starred variant produces an alternative output (which
+displays the root multiplicity), and is provided as an
+example of customization.</p>
+<p>As replacement for <a class="reference internal" href="#polprintintervalsknownroot">\PolPrintIntervalsKnownRoot</a>,
+<a class="reference internal" href="#polprintintervalsprintexactzero">\PolPrintIntervalsPrintExactZero</a>,
+<a class="reference internal" href="#polprintintervalsunknownroot">\PolPrintIntervalsUnknownRoot</a> it uses its own
+<tt class="docutils literal"><span class="pre">\POL&#64;&#64;PrintIntervals...</span></tt> macros. We only reproduce here one
+definition:</p>
+<pre class="literal-block">
+\newcommand\POL&#64;&#64;PrintIntervalsPrintExactZero{%
+ \displaystyle
+ \xintSignedFrac{\PolPrintIntervalsTheLeftEndPoint}%
+}%
+</pre>
+<p>Multiplicities are printed using this auxiliary macro:</p>
+</blockquote>
+<div class="section" id="polprintintervalsprintmultiplicity">
+<h3><a class="toc-backref" href="#id96"><tt class="docutils literal">\PolPrintIntervalsPrintMultiplicity</tt></a></h3>
+<blockquote>
+<p>whose default definition is:</p>
+<pre class="literal-block">
+\newcommand\PolPrintIntervalsPrintMultiplicity{(\mbox{mult. }\PolPrintIntervalsTheMultiplicity)}
+</pre>
+</blockquote>
+</div>
+</div>
+<div class="section" id="polmapcoeffs-macro-polname">
+<span id="polmapcoeffs"></span><h2><a class="toc-backref" href="#id97"><tt class="docutils literal"><span class="pre">\PolMapCoeffs{\macro}{polname}</span></tt></a></h2>
+<blockquote>
+<p>It modifies ('in-place': original coefficients get lost) each
+coefficient of the defined polynomial via the <em>expandable</em> macro
+<tt class="docutils literal">\macro</tt>. The degree is adjusted as necessary if some leading
+coefficients vanish after the operation. In replacement text of
+<tt class="docutils literal">\macro</tt>, <tt class="docutils literal">\index</tt> expands to the coefficient index (which is
+defined to be zero for the constant term).</p>
+<p>Notice that <tt class="docutils literal">\macro</tt> will have to handle inputs of the shape
+<tt class="docutils literal">A/B[N]</tt> (<a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> internal notation). This means that it probably
+will have to be expressed in terms of macros from <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> package.</p>
+<p>Example:</p>
+<pre class="literal-block">
+\def\foo#1{\xintMul{#1}{\the\numexpr\index*\index\relax}}
+</pre>
+<p>(or with <tt class="docutils literal"><span class="pre">\xintSqr{\index}</span></tt>) to replace <tt class="docutils literal">n</tt>-th coefficient
+<tt class="docutils literal">f_n</tt> by <tt class="docutils literal">f_n*n^2</tt>.</p>
+</blockquote>
+</div>
+<div class="section" id="polreducecoeffs-polname">
+<span id="polreducecoeffs"></span><h2><a class="toc-backref" href="#id98"><tt class="docutils literal">\PolReduceCoeffs{polname}</tt></a></h2>
+<blockquote>
+About the same as <tt class="docutils literal"><span class="pre">\PolMapCoeffs{\xintIrr}{polname}</span></tt> (but
+maintaining a <tt class="docutils literal">[0]</tt> postfix for speedier <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> parsing when
+polynomial function is used for computations.) This is a
+one-argument macro, working 'in-place'.</blockquote>
+</div>
+<div class="section" id="id21">
+<span id="id20"></span><h2><a class="toc-backref" href="#id99"><tt class="docutils literal"><span class="pre">\PolReduceCoeffs*{polname}</span></tt></a></h2>
+<blockquote>
+<p>This starred variant leaves un-touched the decimal exponent in the
+internal representation of the fractional coefficients, i.e. if a
+coefficient is internally <tt class="docutils literal">A/B[N]</tt>, then <tt class="docutils literal">A/B</tt> is reduced to
+smallest terms, but the <tt class="docutils literal">10^N</tt> part is kept as is. Note: if the
+polynomial is freshly defined directly via <a class="reference internal" href="#polfromcsv">\PolFromCSV</a> its coefficients might still be internally in some
+format like <tt class="docutils literal">1.5e7</tt>; the macro will anyhow always first do the
+needed conversion to strict format <tt class="docutils literal">A/B[N]</tt>.</p>
+<p>Evaluations with polynomials treated by this can be much faster than
+with those handled by the non-starred variant
+<a class="reference internal" href="#polreducecoeffs-polname">\PolReduceCoeffs{polname}</a>: as the numerators and denominators
+remain smaller, this proves very beneficial in favorable cases
+(especially when the coefficients are decimal numbers) to the
+expansion speed of the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros used internally by
+<a class="reference internal" href="#polevalat">\PolEval</a>.</p>
+</blockquote>
+</div>
+<div class="section" id="polmakemonic-polname">
+<span id="polmakemonic"></span><h2><a class="toc-backref" href="#id100"><tt class="docutils literal">\PolMakeMonic{polname}</tt></a></h2>
+<blockquote>
+Divides by the leading coefficient. It is recommended to execute
+<a class="reference internal" href="#id21">\PolReduceCoeffs*{polname}</a> immediately afterwards. This is not
+done automatically, due to the case the original polynomial had integer
+coefficients and we want to keep the leading one as common
+denominator.</blockquote>
+</div>
+<div class="section" id="polmakeprimitive-polname">
+<span id="polmakeprimitive"></span><h2><a class="toc-backref" href="#id101"><tt class="docutils literal">\PolMakePrimitive{polname}</tt></a></h2>
+<blockquote>
+Divides by the integer content see (<a class="reference internal" href="#policontent">\PolIContent</a>). This thus produces a polynomial with integer
+coefficients having no common factor. The sign of the leading
+coefficient is not modified.</blockquote>
+</div>
+</div>
+<div class="section" id="expandable-macros">
+<h1><a class="toc-backref" href="#id102">Expandable macros</a></h1>
+<p>All these macros expand completely in two steps except <tt class="docutils literal">\PolToExpr</tt>
+and <tt class="docutils literal">\PolToFloatExpr</tt> (and their auxiliaries) which need a
+<tt class="docutils literal">\write</tt>, <tt class="docutils literal">\edef</tt> or a <tt class="docutils literal"><span class="pre">\csname...\endcsname</span></tt> context.</p>
+<div class="section" id="poleval-polname-atexpr-numerical-expression">
+<span id="polevalatexpr"></span><h2><a class="toc-backref" href="#id103"><tt class="docutils literal"><span class="pre">\PolEval{polname}\AtExpr{numerical</span> expression}</tt></a></h2>
+<blockquote>
+It boils down to
+<tt class="docutils literal">\xinttheexpr polname(numerical <span class="pre">expression)\relax</span></tt>.</blockquote>
+</div>
+<div class="section" id="poleval-polname-at-fraction">
+<span id="polevalat"></span><h2><a class="toc-backref" href="#id104"><tt class="docutils literal"><span class="pre">\PolEval{polname}\At{fraction}</span></tt></a></h2>
+<blockquote>
+Evaluates the polynomial at value <tt class="docutils literal">fraction</tt> which must be in (or
+expand to) a format acceptable to the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros.</blockquote>
+</div>
+<div class="section" id="polevalreduced-polname-atexpr-numerical-expression">
+<span id="polevalreducedatexpr"></span><h2><a class="toc-backref" href="#id105"><tt class="docutils literal"><span class="pre">\PolEvalReduced{polname}\AtExpr{numerical</span> expression}</tt></a></h2>
+<blockquote>
+Boils down to <tt class="docutils literal">\xinttheexpr reduce(polname(numerical <span class="pre">expression))\relax</span></tt>.</blockquote>
+</div>
+<div class="section" id="polevalreduced-polname-at-fraction">
+<span id="polevalreducedat"></span><h2><a class="toc-backref" href="#id106"><tt class="docutils literal"><span class="pre">\PolEvalReduced{polname}\At{fraction}</span></tt></a></h2>
+<blockquote>
+Evaluates the polynomial at value <tt class="docutils literal">fraction</tt> which must be in (or
+expand to) a format acceptable to the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros, and produce
+an irreducible fraction.</blockquote>
+</div>
+<div class="section" id="polfloateval-polname-atexpr-numerical-expression">
+<span id="polfloatevalatexpr"></span><h2><a class="toc-backref" href="#id107"><tt class="docutils literal"><span class="pre">\PolFloatEval{polname}\AtExpr{numerical</span> expression}</tt></a></h2>
+<blockquote>
+<p>Boils down to <tt class="docutils literal">\xintthefloatexpr polname(numerical <span class="pre">expression)\relax</span></tt>.</p>
+<p>This is done via a Horner Scheme (see <a class="reference internal" href="#poldef">\poldef</a> and
+<a class="reference internal" href="#polgenfloatvariant-polname">\PolGenFloatVariant{polname}</a>), with already rounded
+coefficients. <a class="footnote-reference" href="#id24" id="id22">[2]</a> To use the <em>exact coefficients</em> with <em>exactly
+executed</em> additions and multiplications, just insert it in the float
+expression as in this example: <a class="footnote-reference" href="#id25" id="id23">[3]</a></p>
+<pre class="literal-block">
+\xintthefloatexpr 3.27*\xintexpr f(2.53)\relax^2\relax
+</pre>
+<p>The <tt class="docutils literal">f(2.53)</tt> is exactly computed then rounded at the time of
+getting raised to the power <tt class="docutils literal">2</tt>. Moving the <tt class="docutils literal">^2</tt> inside, that
+operation would also be treated exactly.</p>
+<table class="docutils footnote" frame="void" id="id24" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id22">[2]</a></td><td>Anyway each floating point operation starts by rounding its
+operands to the floating point precision.</td></tr>
+</tbody>
+</table>
+<table class="docutils footnote" frame="void" id="id25" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id23">[3]</a></td><td>The <tt class="docutils literal">\xintexpr</tt> here could be <tt class="docutils literal">\xinttheexpr</tt> but that
+would be less efficient. Cf. <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> documentation about
+nested expressions.</td></tr>
+</tbody>
+</table>
+</blockquote>
+</div>
+<div class="section" id="polfloateval-polname-at-fraction">
+<span id="polfloatevalat"></span><h2><a class="toc-backref" href="#id108"><tt class="docutils literal"><span class="pre">\PolFloatEval{polname}\At{fraction}</span></tt></a></h2>
+<blockquote>
+Evaluates the polynomial at value <tt class="docutils literal">fraction</tt> which must be in (or
+expand to) a format acceptable to the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros, and produces
+a floating point number.</blockquote>
+</div>
+<div class="section" id="polifcoeffisplusorminusone-a-b">
+<span id="polifcoeffisplusorminusone"></span><h2><a class="toc-backref" href="#id109"><tt class="docutils literal"><span class="pre">\PolIfCoeffIsPlusOrMinusOne{A}{B}</span></tt></a></h2>
+<blockquote>
+<p>This macro is a priori undefined.</p>
+<p>It is defined via the default <a class="reference internal" href="#poltypesetcmd-raw-coeff">\PolTypesetCmd{raw_coeff}</a> to be
+used if needed in the execution of <a class="reference internal" href="#poltypesetmonomialcmd">\PolTypesetMonomialCmd</a>,
+e.g. to insert a <tt class="docutils literal">\cdot</tt> in front of <tt class="docutils literal"><span class="pre">\PolVar^{\PolIndex}</span></tt> if
+the coefficient is not plus or minus one.</p>
+<p>The macro will execute <tt class="docutils literal">A</tt> if the coefficient has been found to be
+plus or minus one, and <tt class="docutils literal">B</tt> if not.</p>
+</blockquote>
+</div>
+<div class="section" id="polleadingcoeff-polname">
+<span id="polleadingcoeff"></span><h2><a class="toc-backref" href="#id110"><tt class="docutils literal">\PolLeadingCoeff{polname}</tt></a></h2>
+<blockquote>
+Expands to the leading coefficient.</blockquote>
+</div>
+<div class="section" id="polnthcoeff-polname-number">
+<span id="polnthcoeff"></span><h2><a class="toc-backref" href="#id111"><tt class="docutils literal"><span class="pre">\PolNthCoeff{polname}{number}</span></tt></a></h2>
+<blockquote>
+It expands to the raw <tt class="docutils literal">N</tt>-th coefficient (<tt class="docutils literal">0/1[0]</tt> if the index
+number is out of range). With <tt class="docutils literal"><span class="pre">N=-1</span></tt>, <tt class="docutils literal"><span class="pre">-2</span></tt>, ... expands to the
+leading coefficients.</blockquote>
+</div>
+<div class="section" id="poldegree-polname">
+<span id="poldegree"></span><h2><a class="toc-backref" href="#id112"><tt class="docutils literal">\PolDegree{polname}</tt></a></h2>
+<blockquote>
+It expands to the degree. This is <tt class="docutils literal"><span class="pre">-1</span></tt> if zero polynomial but this
+may change in future. Should it then expand to <tt class="docutils literal"><span class="pre">-\infty</span></tt> ?</blockquote>
+</div>
+<div class="section" id="policontent-polname">
+<span id="policontent"></span><h2><a class="toc-backref" href="#id113"><tt class="docutils literal">\PolIContent{polname}</tt></a></h2>
+<blockquote>
+<p>It expands to the contents of the polynomial, i.e. to the positive
+fraction such that dividing by this fraction produces a polynomial
+with integer coefficients having no common prime divisor.</p>
+<p>See <a class="reference internal" href="#polmakeprimitive">\PolMakePrimitive</a>.</p>
+</blockquote>
+</div>
+<div class="section" id="poltoexpr-polname">
+<span id="poltoexpr"></span><h2><a class="toc-backref" href="#id114"><tt class="docutils literal">\PolToExpr{polname}</tt></a></h2>
+<blockquote>
+<p>Expands <a class="footnote-reference" href="#id27" id="id26">[4]</a> to <tt class="docutils literal"><span class="pre">coeff_N*x^N+...</span></tt> (descending powers.)</p>
+<table class="docutils footnote" frame="void" id="id27" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id26">[4]</a></td><td>in a <tt class="docutils literal">\write</tt>, <tt class="docutils literal">\edef</tt>, or <tt class="docutils literal"><span class="pre">\csname...\endcsname</span></tt>, but
+not under <tt class="docutils literal"><span class="pre">\romannumeral-`0</span></tt>.</td></tr>
+</tbody>
+</table>
+<p>By default zero coefficients are skipped (issue <tt class="docutils literal">\poltoexpralltrue</tt> to
+get all of them in output).</p>
+<p>By default, no <tt class="docutils literal">+</tt> sign before negative coefficients, for
+compliance with Maple input format (but see
+<a class="reference internal" href="#poltoexprtermprefix-raw-coeff">\PolToExprTermPrefix{raw_coeff}</a>.) Also, like the default
+behaviour of <a class="reference internal" href="#poltypeset-polname">\PolTypeset{polname}</a>, does not print (for the non
+constant terms) coefficients equal to plus or minus one. The degree
+one monomial is output as <tt class="docutils literal">x</tt>, not <tt class="docutils literal">x^1</tt>. Complete customization is
+possible, see next macros.</p>
+<p>Of course <tt class="docutils literal">\PolToExpr{f}</tt> can be inserted in a <tt class="docutils literal">\poldef</tt>, as the
+latter expands token by token, hence will force complete expansion
+of <tt class="docutils literal">\PolToExpr{f}</tt>, but a simple <tt class="docutils literal">f(x)</tt> is more efficient for
+the identical result.</p>
+</blockquote>
+<div class="section" id="poltoexproneterm-raw-coeff-number">
+<span id="poltoexproneterm"></span><h3><a class="toc-backref" href="#id115"><tt class="docutils literal"><span class="pre">\PolToExprOneTerm{raw_coeff}{number}</span></tt></a></h3>
+<blockquote>
+<p>This two argument expandable command takes care of the monomial and
+its coefficient. The default definition is done in order for
+coefficients of absolute value <tt class="docutils literal">1</tt> not be printed explicitely
+(except of course for the constant term). Also by default, the
+monomial of degree one is <tt class="docutils literal">x</tt> not <tt class="docutils literal">x^1</tt>, and <tt class="docutils literal">x^0</tt> is skipped.</p>
+<p>For compatibility with Maple input requirements, by default a <tt class="docutils literal">*</tt>
+always precedes the <tt class="docutils literal">x^number</tt>, except if the coefficient is a one
+or a minus one. See <a class="reference internal" href="#poltoexprtimes">\PolToExprTimes</a>.</p>
+</blockquote>
+</div>
+<div class="section" id="poltoexpronetermstylea-raw-coeff-number">
+<span id="poltoexpronetermstylea"></span><h3><a class="toc-backref" href="#id116"><tt class="docutils literal"><span class="pre">\PolToExprOneTermStyleA{raw_coeff}{number}</span></tt></a></h3>
+<blockquote>
+Holds the default package meaning of
+<a class="reference internal" href="#poltoexproneterm-raw-coeff-number">\PolToExprOneTerm{raw_coeff}{number}</a>.</blockquote>
+</div>
+<div class="section" id="poltoexpronetermstyleb-raw-coeff-number">
+<span id="poltoexpronetermstyleb"></span><h3><a class="toc-backref" href="#id117"><tt class="docutils literal"><span class="pre">\PolToExprOneTermStyleB{raw_coeff}{number}</span></tt></a></h3>
+<blockquote>
+<p>For output in this style:</p>
+<pre class="literal-block">
+2*x^11/3+3*x^8/7-x^5-x^4/4-x^3-x^2/2-2*x+1
+</pre>
+<p>issue <tt class="docutils literal">\let\PolToExprOneTerm\PolToExprOneTermStyleB</tt> before usage of
+<tt class="docutils literal">\PolToExpr</tt>. Note that then <tt class="docutils literal">\PolToExprCmd</tt> isn't used at all.
+To revert to package default, issue
+<tt class="docutils literal">\let\PolToExprOneTerm\PolToExprOneTermStyleA</tt>.</p>
+<p>To suppress the <tt class="docutils literal">*</tt>'s, cf. <a class="reference internal" href="#poltoexprtimes">\PolToExprTimes</a>.</p>
+</blockquote>
+</div>
+<div class="section" id="poltoexprcmd-raw-coeff">
+<span id="poltoexprcmd"></span><h3><a class="toc-backref" href="#id118"><tt class="docutils literal">\PolToExprCmd{raw_coeff}</tt></a></h3>
+<blockquote>
+It is the one-argument macro used by the package definition of
+<tt class="docutils literal">\PolToExprOneTerm</tt> for the coefficients themselves (when not
+equal to plus or minus one), and it defaults to
+<tt class="docutils literal"><span class="pre">\xintPRaw{\xintRawWithZeros{#1}}</span></tt>. One will have to redefine it
+to <tt class="docutils literal"><span class="pre">\xintIrr{#1}</span></tt> or to <tt class="docutils literal"><span class="pre">\xintPRaw{\xintIrr{#1}}</span></tt> to obtain in the
+output forcefully reduced coefficients.</blockquote>
+</div>
+<div class="section" id="poltoexprtermprefix-raw-coeff">
+<span id="poltoexprtermprefix"></span><h3><a class="toc-backref" href="#id119"><tt class="docutils literal">\PolToExprTermPrefix{raw_coeff}</tt></a></h3>
+<blockquote>
+Defined identically as <a class="reference internal" href="#poltypesetcmdprefix-raw-coeff">\PolTypesetCmdPrefix{raw_coeff}</a>. It
+prefixes with a plus sign for non-negative coefficients, because
+they don't carry one by themselves.</blockquote>
+</div>
+<div class="section" id="id28">
+<span id="poltoexprvar"></span><h3><a class="toc-backref" href="#id120"><tt class="docutils literal">\PolToExprVar</tt></a></h3>
+<blockquote>
+This expands to the variable to use in output (it does not have to
+be a single letter, may be an expandable macro.) Initial definition
+is <tt class="docutils literal">x</tt>.</blockquote>
+</div>
+<div class="section" id="id29">
+<span id="poltoexprtimes"></span><h3><a class="toc-backref" href="#id121"><tt class="docutils literal">\PolToExprTimes</tt></a></h3>
+<blockquote>
+This expands to the symbol used for multiplication of an
+<tt class="docutils literal"><span class="pre">x^{number}</span></tt> by the corresponding coefficient. The default is
+<tt class="docutils literal">*</tt>. Redefine the macro to expand to nothing to get rid of it (but
+this will give output incompatible with some professional computer
+algebra software).</blockquote>
+</div>
+</div>
+<div class="section" id="id31">
+<span id="id30"></span><h2><a class="toc-backref" href="#id122"><tt class="docutils literal"><span class="pre">\PolToExpr*{polname}</span></tt></a></h2>
+<blockquote>
+Expands to <tt class="docutils literal"><span class="pre">coeff_0+coeff_1*x+coeff_2*x^2+...</span></tt> (ascending powers).
+Customizable like <a class="reference internal" href="#poltoexpr-polname">\PolToExpr{polname}</a> via the same macros.</blockquote>
+</div>
+<div class="section" id="poltofloatexpr-polname">
+<span id="poltofloatexpr"></span><h2><a class="toc-backref" href="#id123"><tt class="docutils literal">\PolToFloatExpr{polname}</tt></a></h2>
+<blockquote>
+<p>Similar to <a class="reference internal" href="#poltoexpr-polname">\PolToExpr{polname}</a> but uses <a class="reference external" href="\PolToFloatExprCmd{raw_coeff}">\PolToFloatExprCmd</a>
+which by default rounds and converts the coefficients to floating
+point format.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p>It is not necessary to have issued
+<a class="reference internal" href="#polgenfloatvariant-polname">\PolGenFloatVariant{polname}</a>. The rounded coefficients are
+not easily recoverable from the <tt class="docutils literal">\xintfloatexpr</tt> polynomial
+function hence <tt class="docutils literal">\PolToFloatExprCmd</tt> operates from the <em>exact</em>
+coefficients anew.</p>
+<p class="last">Attention that both macros obey the prevailing float precision.
+If it is changed between those macro calls, then a mismatch
+exists between the coefficients as used in <tt class="docutils literal">\xintfloatexpr</tt> and
+those output by <tt class="docutils literal">\PolToFloatExpr{polname}</tt>.</p>
+</div>
+</blockquote>
+<div class="section" id="poltofloatexproneterm-raw-coeff-number">
+<span id="poltofloatexproneterm"></span><h3><a class="toc-backref" href="#id124"><tt class="docutils literal"><span class="pre">\PolToFloatExprOneTerm{raw_coeff}{number}</span></tt></a></h3>
+<blockquote>
+Similar to <a class="reference external" href="\PolToExprOneTerm{raw_coeff}{number}">\PolToExprOneTerm</a>. But does not treat
+especially coefficients equal to plus or minus one.</blockquote>
+</div>
+<div class="section" id="poltofloatexprcmd-raw-coeff">
+<span id="id33"></span><h3><a class="toc-backref" href="#id125"><tt class="docutils literal">\PolToFloatExprCmd{raw_coeff}</tt></a></h3>
+<blockquote>
+<p>It is the one-argument macro used by <tt class="docutils literal">\PolToFloatExprOneTerm</tt>.
+Its package definition is <tt class="docutils literal"><span class="pre">\xintFloat{#1}</span></tt>.</p>
+<div class="admonition caution">
+<p class="first admonition-title">Caution!</p>
+<p>Currently (<a class="reference external" href="http://www.ctan.org/pkg/xint">xint</a> <tt class="docutils literal">1.3c</tt>) <tt class="docutils literal">\xintFloat{0}</tt> outputs <tt class="docutils literal">0.e0</tt>
+which is perfectly acceptable input for Python, but not for
+Maple. Thus, one should better leave the <a class="reference internal" href="#poltoexprallfalse">\poltoexprallfalse</a>
+toggle to its default <tt class="docutils literal">\iffalse</tt> state, if one intends to use
+the output in a Maple worksheet.</p>
+<p>But even then the zero polynomial will cause a problem. Workaround:</p>
+<pre class="literal-block">
+\renewcommand\PolToFloatExprCmd[1]{\xintiiifZero{#1}{0.0}{\xintFloat{#1}}}
+</pre>
+<p class="last">Usage of <tt class="docutils literal">\xintiiifZero</tt> and not <tt class="docutils literal">\xintifZero</tt> is only for
+optimization (I can't help it) because <tt class="docutils literal">#1</tt> is known to be
+in <tt class="docutils literal">xintfrac</tt> raw format.</p>
+</div>
+</blockquote>
+</div>
+</div>
+<div class="section" id="id35">
+<span id="id34"></span><h2><a class="toc-backref" href="#id126"><tt class="docutils literal"><span class="pre">\PolToFloatExpr*{polname}</span></tt></a></h2>
+<blockquote>
+Typesets in ascending powers.</blockquote>
+</div>
+<div class="section" id="poltolist-polname">
+<span id="poltolist"></span><h2><a class="toc-backref" href="#id127"><tt class="docutils literal">\PolToList{polname}</tt></a></h2>
+<blockquote>
+Expands to <tt class="docutils literal"><span class="pre">{coeff_0}{coeff_1}...{coeff_N}</span></tt> with <tt class="docutils literal">N</tt> = degree, and
+<tt class="docutils literal">coeff_N</tt> the leading coefficient
+(the zero polynomial does give <tt class="docutils literal">{0/1[0]}</tt> and not an
+empty output.)</blockquote>
+</div>
+<div class="section" id="poltocsv-polname">
+<span id="poltocsv"></span><h2><a class="toc-backref" href="#id128"><tt class="docutils literal">\PolToCSV{polname}</tt></a></h2>
+<blockquote>
+Expands to <tt class="docutils literal">coeff_0, coeff_1, coeff_2, <span class="pre">.....,</span> coeff_N</tt>, starting
+with constant term and ending with leading coefficient. Converse
+to <a class="reference internal" href="#polfromcsv-polname-csv">\PolFromCSV</a>.</blockquote>
+</div>
+<div class="section" id="polsturmchainlength-sturmname">
+<span id="polsturmchainlength"></span><h2><a class="toc-backref" href="#id129"><tt class="docutils literal">\PolSturmChainLength{sturmname}</tt></a></h2>
+<blockquote>
+<p>Returns the integer <tt class="docutils literal">N</tt> such that <tt class="docutils literal">sturmname_N</tt> is the last one
+in the Sturm chain <tt class="docutils literal">sturmname_0</tt>, <tt class="docutils literal">sturmname_1</tt>, ...</p>
+<p>See <a class="reference internal" href="#poltosturm-polname-sturmname">\PolToSturm{polname}{sturmname}</a>.</p>
+</blockquote>
+</div>
+<div class="section" id="polsturmifzeroexactlyknown-sturmname-index-a-b">
+<span id="polsturmifzeroexactlyknown"></span><h2><a class="toc-backref" href="#id130"><tt class="docutils literal"><span class="pre">\PolSturmIfZeroExactlyKnown{sturmname}{index}{A}{B}</span></tt></a></h2>
+<blockquote>
+<p>Executes <tt class="docutils literal">A</tt> if the <tt class="docutils literal">index</tt>-th interval reduces to a singleton,
+i.e. the root is known exactly, else <tt class="docutils literal">B</tt>.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last"><tt class="docutils literal">index</tt> is allowed to be something like <tt class="docutils literal">1+2*3</tt> as it is fed
+to <tt class="docutils literal"><span class="pre">\the\numexpr...\relax</span></tt>.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polsturmisolatedzeroleft-sturmname-index">
+<span id="polsturmisolatedzeroleft"></span><h2><a class="toc-backref" href="#id131"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroLeft{sturmname}{index}</span></tt></a></h2>
+<blockquote>
+<p>Expands to the left end-point for the <tt class="docutils literal">index</tt>-th interval, as
+computed by some earlier <a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a>.</p>
+<div class="admonition note">
+<p class="first admonition-title">Note</p>
+<p class="last">Of course, this is kept updated by macros such as
+<a class="reference internal" href="#polrefineinterval-n">\PolRefineInterval{sturmname}{index}</a>.</p>
+</div>
+<p>The value is pre-formatted using <a class="reference internal" href="#poldectostring">\PolDecTostring</a>.</p>
+</blockquote>
+</div>
+<div class="section" id="polsturmisolatedzeroright-sturmname-index">
+<span id="polsturmisolatedzeroright"></span><h2><a class="toc-backref" href="#id132"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroRight{sturmname}{index}</span></tt></a></h2>
+<blockquote>
+<p>Expands to the right end-point for the <tt class="docutils literal">index</tt>-th interval as
+computed by some earlier <a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a> and
+possibly refined afterwards.</p>
+<p>The value is pre-formatted using <a class="reference internal" href="#poldectostring">\PolDecTostring</a>.</p>
+</blockquote>
+</div>
+<div class="section" id="polsturmisolatedzeromultiplicity-sturmname-index">
+<span id="polsturmisolatedzeromultiplicity"></span><h2><a class="toc-backref" href="#id133"><tt class="docutils literal"><span class="pre">\PolSturmIsolatedZeroMultiplicity{sturmname}{index}</span></tt></a></h2>
+<blockquote>
+<p>Expands to the multiplicity of the unique root contained in the
+<tt class="docutils literal">index</tt>-th interval.</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last">A prior execution of <a class="reference internal" href="#id12">\PolSturmIsolateZeros*{sturmname}</a> is mandatory.</p>
+</div>
+<p>See <a class="reference internal" href="#the-degree-nine-polynomial-with-0-99-0-999-0-9999-as-triple-roots">The degree nine polynomial with 0.99, 0.999, 0.9999 as triple
+roots</a> for an example of use.</p>
+</blockquote>
+</div>
+<div class="section" id="polsturmnbofisolatedzeros-sturmname">
+<span id="polsturmnbofisolatedzeros"></span><h2><a class="toc-backref" href="#id134"><tt class="docutils literal">\PolSturmNbOfIsolatedZeros{sturmname}</tt></a></h2>
+<blockquote>
+Expands to the number of real roots of the polynomial
+<tt class="docutils literal">&lt;sturmname&gt;_0</tt>, i.e. the number of distinct real roots of the
+polynomial originally used to create the Sturm chain via
+<a class="reference internal" href="#poltosturm-polname-sturmname">\PolToSturm{polname}{sturmname}</a>.</blockquote>
+<div class="admonition warning">
+<p class="first admonition-title">Warning</p>
+<p class="last">The next few macros counting roots, with or without multiplicities,
+less than or equal to some value, are under evaluation and may be
+removed from the package if their utility is judged to be not high
+enough. They can be re-coded at user level on the basis of the other
+documented package macros anyway.</p>
+</div>
+<div class="section" id="polsturmnbofrootsof-sturmname-lessthanorequalto-value">
+<h3><a class="toc-backref" href="#id135"><tt class="docutils literal"><span class="pre">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}</span></tt></a></h3>
+<blockquote>
+<p>Expands to the number of distinct roots (of the polynomial used to
+create the Sturm chain) less than or equal to the <tt class="docutils literal">value</tt> (i.e. a
+number of fraction recognizable by the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros).</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p><a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a> must have been executed
+beforehand.</p>
+<p class="last">And the argument is a <tt class="docutils literal">sturmname</tt>, not a <tt class="docutils literal">polname</tt> (this is
+why the macro contains Sturm in its name), simply to be reminded
+of the above constraint.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polsturmnbofrootsof-sturmname-lessthanorequaltoexpr-expression">
+<h3><a class="toc-backref" href="#id136"><tt class="docutils literal"><span class="pre">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</span></tt></a></h3>
+<blockquote>
+<p>Expands to the number of distinct roots (of the polynomial
+used to create the Sturm chain) which are less than or equal to the
+given <tt class="docutils literal">expression</tt>.</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last"><a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a> must have been executed
+beforehand.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polsturmnbwithmultofrootsof-sturmname-lessthanorequalto-value">
+<h3><a class="toc-backref" href="#id137"><tt class="docutils literal"><span class="pre">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualTo{value}</span></tt></a></h3>
+<blockquote>
+<p>Expands to the number counted with multiplicities of the roots (of
+the polynomial used to create the Sturm chain) which are less than
+or equal to the given <tt class="docutils literal">value</tt>.</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last"><a class="reference internal" href="#id12">\PolSturmIsolateZeros*{sturmname}</a> (or the double starred
+variant) must have been executed beforehand.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polsturmnbwithmultofrootsof-sturmname-lessthanorequaltoexpr-expression">
+<h3><a class="toc-backref" href="#id138"><tt class="docutils literal"><span class="pre">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</span></tt></a></h3>
+<blockquote>
+<p>Expands to the total number of roots (counted with multiplicities)
+which are less than or equal to the given <tt class="docutils literal">expression</tt>.</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last"><a class="reference internal" href="#id12">\PolSturmIsolateZeros*{sturmname}</a> (or the double starred
+variant) must have been executed beforehand.</p>
+</div>
+</blockquote>
+</div>
+</div>
+<div class="section" id="polsturmnbofrationalroots-sturmname">
+<h2><a class="toc-backref" href="#id139"><tt class="docutils literal">\PolSturmNbOfRationalRoots{sturmname}</tt></a></h2>
+<blockquote>
+<p>Expands to the number of rational roots (without multiplicities).</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last"><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> must have been executed
+beforehand.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polsturmnbofrationalrootswithmultiplicities-sturmname">
+<h2><a class="toc-backref" href="#id140"><tt class="docutils literal">\PolSturmNbOfRationalRootsWithMultiplicities{sturmname}</tt></a></h2>
+<blockquote>
+<p>Expands to the number of rational roots (counted with multiplicities).</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last"><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> must have been executed
+beforehand.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polsturmrationalroot-sturmname-k">
+<h2><a class="toc-backref" href="#id141"><tt class="docutils literal"><span class="pre">\PolSturmRationalRoot{sturmname}{k}</span></tt></a></h2>
+<blockquote>
+<p>Expands to the <tt class="docutils literal">k</tt>th rational root (they are ordered and indexed
+starting at 1 for the most negative).</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last"><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> must have been executed
+beforehand.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polsturmrationalrootindex-sturmname-k">
+<h2><a class="toc-backref" href="#id142"><tt class="docutils literal"><span class="pre">\PolSturmRationalRootIndex{sturmname}{k}</span></tt></a></h2>
+<blockquote>
+<p>Expands to <tt class="docutils literal">index</tt> of the <tt class="docutils literal">k</tt>th rational root as part of the
+ordered real roots (without multiplicities). I.e., above macro
+<a class="reference internal" href="#polsturmrationalroot-sturmname-k">\PolSturmRationalRoot{sturmname}{k}</a> is equivalent to this
+nested call:</p>
+<pre class="literal-block">
+\PolSturmIsolatedZeroLeft{sturmname}{\PolSturmRationalRootIndex{sturmname}{k}}
+</pre>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last"><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> must have been executed
+beforehand.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polsturmrationalrootmultiplicity-sturmname-k">
+<h2><a class="toc-backref" href="#id143"><tt class="docutils literal"><span class="pre">\PolSturmRationalRootMultiplicity{sturmname}{k}</span></tt></a></h2>
+<blockquote>
+<p>Expands to the multiplicity of the <tt class="docutils literal">k</tt>th rational root.</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last"><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a> must have been executed
+beforehand.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="polintervalwidth-sturmname-index">
+<span id="polintervalwidth"></span><h2><a class="toc-backref" href="#id144"><tt class="docutils literal"><span class="pre">\PolIntervalWidth{sturmname}{index}</span></tt></a></h2>
+<blockquote>
+The <tt class="docutils literal">10^E</tt> width of the current <tt class="docutils literal">index</tt>-th root localization
+interval. Output is in <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> raw <tt class="docutils literal">1/1[E]</tt> format (if not zero).</blockquote>
+</div>
+<div class="section" id="expandable-macros-for-use-within-execution-of-polprintintervals">
+<h2><a class="toc-backref" href="#id145">Expandable macros for use within execution of <tt class="docutils literal">\PolPrintIntervals</tt></a></h2>
+<p>These macros are for usage within custom user redefinitions of
+<a class="reference internal" href="#polprintintervalsknownroot">\PolPrintIntervalsKnownRoot</a>, <a class="reference internal" href="#polprintintervalsunknownroot">\PolPrintIntervalsUnknownRoot</a>, or
+in redefinitions of <a class="reference internal" href="#polprintintervalsprintexactzero">PolPrintIntervalsPrintExactZero</a> (used in the
+default for the former) and of <a class="reference internal" href="#polprintintervalsprintleftendpoint">\PolPrintIntervalsPrintLeftEndPoint</a>,
+<a class="reference internal" href="#polprintintervalsprintrightendpoint">\PolPrintIntervalsPrintRightEndPoint</a> (used in the default for the
+latter).</p>
+<div class="admonition attention">
+<p class="first admonition-title">Attention!</p>
+<p class="last">Some macros formerly mentioned here got removed at 0.7:
+<tt class="docutils literal">\PolPrintIntervalsTheEndPoint</tt>,
+<tt class="docutils literal"><span class="pre">\PolIfEndPointIsPositive{A}{B}</span></tt>,
+<tt class="docutils literal"><span class="pre">\PolIfEndPointIsNegative{A}{B}</span></tt>,
+<tt class="docutils literal"><span class="pre">\PolIfEndPointIsZero{A}{B}</span></tt>.</p>
+</div>
+<div class="section" id="polprintintervalsthevar">
+<h3><a class="toc-backref" href="#id146"><tt class="docutils literal">\PolPrintIntervalsTheVar</tt></a></h3>
+<blockquote>
+Expands to the name (default <tt class="docutils literal">Z</tt>) used for representing the roots,
+which was passed as optional argument <tt class="docutils literal">varname</tt> to
+<a class="reference internal" href="#polprintintervals-varname-sturmname">\PolPrintIntervals[varname]{sturmname}</a>.</blockquote>
+</div>
+<div class="section" id="polprintintervalstheindex">
+<h3><a class="toc-backref" href="#id147"><tt class="docutils literal">\PolPrintIntervalsTheIndex</tt></a></h3>
+<blockquote>
+Expands to the index of the considered interval (indexing starting
+at 1 for the leftmost interval).</blockquote>
+</div>
+<div class="section" id="polprintintervalsthesturmname">
+<h3><a class="toc-backref" href="#id148"><tt class="docutils literal">\PolPrintIntervalsTheSturmName</tt></a></h3>
+<blockquote>
+Expands to the argument which was passed as <tt class="docutils literal">sturmname</tt> to
+<a class="reference internal" href="#polprintintervals-varname-sturmname">\PolPrintIntervals[varname]{sturmname}</a>.</blockquote>
+</div>
+<div class="section" id="polprintintervalstheleftendpoint">
+<h3><a class="toc-backref" href="#id149"><tt class="docutils literal">\PolPrintIntervalsTheLeftEndPoint</tt></a></h3>
+<blockquote>
+The left end point of the interval, as would be produced by
+<a class="reference internal" href="#polsturmisolatedzeroleft">\PolSturmIsolatedZeroLeft</a> if it was
+used with arguments the Sturm chain name and interval index returned
+by <a class="reference internal" href="#polprintintervalsthesturmname">\PolPrintIntervalsTheSturmName</a> and
+<a class="reference internal" href="#polprintintervalstheindex">\PolPrintIntervalsTheIndex</a>.</blockquote>
+</div>
+<div class="section" id="polprintintervalstherightendpoint">
+<h3><a class="toc-backref" href="#id150"><tt class="docutils literal">\PolPrintIntervalsTheRightEndPoint</tt></a></h3>
+<blockquote>
+The right end point of the interval, as would be produced by
+<a class="reference internal" href="#polsturmisolatedzeroright">\PolSturmIsolatedZeroRight</a> for
+this Sturm chain name and index.</blockquote>
+</div>
+<div class="section" id="polprintintervalsthemultiplicity">
+<h3><a class="toc-backref" href="#id151"><tt class="docutils literal">\PolPrintIntervalsTheMultiplicity</tt></a></h3>
+<blockquote>
+The multiplicity of the unique root within the interval of index
+<a class="reference internal" href="#polprintintervalstheindex">\PolPrintIntervalsTheIndex</a>. Makes sense only if the starred (or
+double-starred) variant of <a class="reference internal" href="#polsturmisolatezeros">\PolSturmIsolateZeros</a> was used earlier.</blockquote>
+</div>
+</div>
+<div class="section" id="poldectostring-decimal-number">
+<span id="poldectostring"></span><h2><a class="toc-backref" href="#id152"><tt class="docutils literal">\PolDecToString{decimal number}</tt></a></h2>
+<blockquote>
+<p>This is a utility macro to print decimal numbers. It has been
+backported to <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> (release <tt class="docutils literal">1.3</tt> of <tt class="docutils literal">2018/03/01</tt>) under
+the name <tt class="docutils literal">\xintDecToString</tt>, and the <tt class="docutils literal">polexpr</tt> macro is simply
+now an alias to it.</p>
+<p>For example
+<tt class="docutils literal"><span class="pre">\PolDecToString{123.456e-8}</span></tt> will expand to <tt class="docutils literal">0.00000123456</tt>
+and <tt class="docutils literal"><span class="pre">\PolDecToString{123.450e-8}</span></tt> to <tt class="docutils literal">0.00000123450</tt> which
+illustrates that trailing zeros are not trimmed. To trim trailing
+zeroes, one can use <tt class="docutils literal"><span class="pre">\PolDecToString{\xintREZ{#1}}</span></tt>.</p>
+<p>The precise behaviour of this macro may evolve in future releases of
+<a class="reference external" href="http://www.ctan.org/pkg/xint">xint</a>.</p>
+</blockquote>
+</div>
+</div>
+<div class="section" id="booleans-with-default-setting-as-indicated">
+<h1><a class="toc-backref" href="#id153">Booleans (with default setting as indicated)</a></h1>
+<div class="section" id="xintverbosefalse">
+<h2><a class="toc-backref" href="#id154"><tt class="docutils literal">\xintverbosefalse</tt></a></h2>
+<blockquote>
+<p>This is actually an <a class="reference external" href="http://www.ctan.org/pkg/xint">xintexpr</a> configuration. Setting it to
+<tt class="docutils literal">true</tt> triggers the writing of information to the log when new
+polynomials are defined.</p>
+<div class="admonition caution">
+<p class="first admonition-title">Caution!</p>
+<p class="last">The macro meanings as written to the log are to be considered
+unstable and undocumented internal structures.</p>
+</div>
+</blockquote>
+</div>
+<div class="section" id="poltypesetallfalse">
+<h2><a class="toc-backref" href="#id155"><tt class="docutils literal">\poltypesetallfalse</tt></a></h2>
+<blockquote>
+If <tt class="docutils literal">true</tt>, <a class="reference internal" href="#poltypeset-polname">\PolTypeset{polname}</a> will also typeset the vanishing
+coefficients.</blockquote>
+</div>
+<div class="section" id="poltoexprallfalse">
+<h2><a class="toc-backref" href="#id156"><tt class="docutils literal">\poltoexprallfalse</tt></a></h2>
+<blockquote>
+If <tt class="docutils literal">true</tt>, <a class="reference internal" href="#poltoexpr-polname">\PolToExpr{polname}</a> and <a class="reference internal" href="#poltofloatexpr-polname">\PolToFloatExpr{polname}</a> will
+also include the vanishing coefficients in their outputs.</blockquote>
+</div>
+</div>
+<div class="section" id="polexprsetup">
+<h1><a class="toc-backref" href="#id157"><tt class="docutils literal">\polexprsetup</tt></a></h1>
+<blockquote>
+<p>Serves to customize the package. Currently only two keys are
+recognized:</p>
+<ul class="simple">
+<li><tt class="docutils literal">norr</tt>: the postfix that <a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a>
+should append to <tt class="docutils literal">sturmname</tt> to declare the primitive polynomial
+obtained from original one after removal of all rational roots.
+The default value is <tt class="docutils literal">_norr</tt> (standing for “no rational roots”).</li>
+<li><tt class="docutils literal">sqfnorr</tt>: the postfix that <a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a>
+should append to <tt class="docutils literal">sturmname</tt> to declare the primitive polynomial
+obtained from original one after removal of all rational roots and
+suppression of all multiplicities.
+The default value is <tt class="docutils literal">_sqf_norr</tt> (standing for “square-free with
+no rational roots”).</li>
+</ul>
+<p>The package executes <tt class="docutils literal">\polexprsetup{norr=_norr,
+sqfnorr=_sqf_norr}</tt> as default.</p>
+</blockquote>
+</div>
+<div class="section" id="technicalities">
+<h1><a class="toc-backref" href="#id158">Technicalities</a></h1>
+<ul>
+<li><p class="first">The catcode of the semi-colon is reset temporarily by <a class="reference internal" href="#poldef">\poldef</a> macro in case some other package (for example the French
+babel module) may have made it active. This will fail though if the
+whole thing was already part of a macro argument, in such cases one
+can use <a class="reference internal" href="#id2">\PolDef{f}{P(x)}</a>
+rather. The colon in <tt class="docutils literal">:=</tt> may be active with no consequences.</p>
+</li>
+<li><p class="first">As a consequence of <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> addition and subtraction always using
+least common multiples for the denominators <a class="footnote-reference" href="#id37" id="id36">[5]</a>, user-chosen common
+denominators survive additions and multiplications. For example, this:</p>
+<pre class="literal-block">
+\poldef P(x):= 1/2 + 2/2*x + 3/2*x^3 + 4/2*x^4;
+\poldef Q(x):= 1/3 + (2/3)x + (3/3)x^3 + (4/3)x^4;
+\poldef PQ(x):= P(x)Q(x);
+</pre>
+<p>gives internally the polynomial:</p>
+<pre class="literal-block">
+1/6+4/6*x^1+4/6*x^2+6/6*x^3+20/6*x^4+16/6*x^5+9/6*x^6+24/6*x^7+16/6*x^8
+</pre>
+<p>where all coefficients have the same denominator 6. Notice though that
+<tt class="docutils literal">\PolToExpr{PQ}</tt> outputs the <tt class="docutils literal">6/6*x^3</tt> as <tt class="docutils literal">x^3</tt> because (by
+default) it recognizes and filters out coefficients equal to one or
+minus one (since release <tt class="docutils literal">0.3</tt>). One can use for example
+<tt class="docutils literal">\PolToCSV{PQ}</tt> to see the internally stored coefficients.</p>
+<table class="docutils footnote" frame="void" id="id37" rules="none">
+<colgroup><col class="label" /><col /></colgroup>
+<tbody valign="top">
+<tr><td class="label"><a class="fn-backref" href="#id36">[5]</a></td><td><p class="first last">prior to <tt class="docutils literal">0.4.1</tt>, <tt class="docutils literal">polexpr</tt> used to temporarily patch
+during the parsing of polynomials the <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a> macros. This
+patch was backported to <a class="reference external" href="http://www.ctan.org/pkg/xint">xint</a> at release <tt class="docutils literal">1.3</tt>.</p>
+</td></tr>
+</tbody>
+</table>
+</li>
+<li><p class="first"><a class="reference internal" href="#poldiff-polname-1-polname-2">\PolDiff{polname_1}{polname_2}</a> always applies <tt class="docutils literal">\xintIrr</tt> to the
+resulting coefficients, except that the <em>power of ten</em> part <tt class="docutils literal">[N]</tt>
+(for example an input in scientific notation such as <tt class="docutils literal">1.23e5</tt> gives
+<tt class="docutils literal">123/1[3]</tt> internally in xintfrac) is not taken into account in the
+reduction of the fraction. This is tentative and may change.</p>
+<p>Same remark for <a class="reference internal" href="#polantidiff-polname-1-polname-2">\PolAntiDiff{polname_1}{polname_2}</a>.</p>
+</li>
+<li><p class="first">Currently, the package stores all coefficients from index <tt class="docutils literal">0</tt> to
+index equal to the polynomial degree inside a single macro, as a list.
+This data structure is obviously very inefficient for polynomials of
+high degree and few coefficients (as an example with <tt class="docutils literal">\poldef
+<span class="pre">f(x):=x^1000</span> + x^500;</tt> the subsequent definition <tt class="docutils literal">\poldef <span class="pre">g(x):=</span>
+<span class="pre">f(x)^2;</span></tt> will do of the order of 1,000,000 multiplications and
+additions involvings only zeroes... which does take time). This
+may change in the future.</p>
+</li>
+<li><p class="first">As is to be expected internal structures of the package are barely
+documented and unstable. Don't use them.</p>
+</li>
+</ul>
+</div>
+<div class="section" id="change-log">
+<h1><a class="toc-backref" href="#id159">CHANGE LOG</a></h1>
+<ul>
+<li><p class="first">v0.1 (2018/01/11): initial release. Features:</p>
+<ul class="simple">
+<li>The <a class="reference internal" href="#poldef">\poldef</a> parser itself,</li>
+<li>Differentiation and anti-differentiation,</li>
+<li>Euclidean division and GCDs,</li>
+<li>Various utilities such as <a class="reference internal" href="#polfromcsv">\PolFromCSV</a>,
+<a class="reference internal" href="#polmapcoeffs">\PolMapCoeffs</a>,
+<a class="reference internal" href="#poltocsv">\PolToCSV</a>, <a class="reference internal" href="#poltoexpr">\PolToExpr</a>, ...</li>
+</ul>
+<p>Only one-variable polynomials so far.</p>
+</li>
+<li><p class="first">v0.2 (2018/01/14)</p>
+<ul class="simple">
+<li>Fix: <tt class="docutils literal">&quot;README thinks \numexpr recognizes ^ operator&quot;</tt>.</li>
+<li>Convert README to reStructuredText markup.</li>
+<li>Move main documentation from README to separate <tt class="docutils literal">polexpr.txt</tt> file.</li>
+<li>Provide <tt class="docutils literal">polexpr.html</tt> as obtained via <a class="reference external" href="http://docutils.sourceforge.net/docs/index.html">DocUtils</a> <tt class="docutils literal">rst2html.py</tt>.</li>
+<li>Convert README to (CTAN compatible) Markdown markup.</li>
+</ul>
+<p>Due to lack of available time the test suite might not be extensive
+enough. Bug reports are very welcome!</p>
+</li>
+<li><p class="first">v0.3 (2018/01/17)</p>
+<ul>
+<li><p class="first">bug fixes:</p>
+<ul>
+<li><p class="first">the <tt class="docutils literal">0.1</tt> <a class="reference internal" href="#polevalat">\PolEval</a> accepted expressions for its second
+argument, but this was removed by mistake at <tt class="docutils literal">0.2</tt>. Restored.</p>
+<p><strong>Attention</strong>: at <tt class="docutils literal">0.4</tt> this has been reverted again, and
+<a class="reference internal" href="#polevalatexpr">\PolEval{P}\AtExpr{foo}</a> syntax is needed for
+using expressions in the second argument.</p>
+</li>
+</ul>
+</li>
+<li><p class="first">incompatible or breaking changes:</p>
+<ul class="simple">
+<li><a class="reference internal" href="#poltoexpr">\PolToExpr</a> now by default uses <em>descending</em>
+powers (it also treats differently coefficients equal to 1 or -1.)
+Use <a class="reference internal" href="#id30">\PolToExpr*</a> for <em>ascending</em> powers.</li>
+<li><a class="reference internal" href="#polevalat">\PolEval</a> reduced the output to smallest terms,
+but as this is costly with big fractions and not needed if e.g.
+wrapped in an <tt class="docutils literal">\xintRound</tt> or <tt class="docutils literal">\xintFloat</tt>, this step has been
+removed; the former meaning is available as <a class="reference internal" href="#polevalreducedat">\PolEvalReduced</a>.</li>
+</ul>
+</li>
+<li><p class="first">new (or newly documented) macros:</p>
+<ul class="simple">
+<li><a class="reference internal" href="#poltypesetcmd">\PolTypesetCmd</a></li>
+<li><a class="reference internal" href="#poltypesetcmdprefix">\PolTypesetCmdPrefix</a></li>
+<li><a class="reference internal" href="#poltypesetmonomialcmd">\PolTypesetMonomialCmd</a></li>
+<li><a class="reference internal" href="#polevalreducedat">\PolEvalReducedAt</a></li>
+<li><a class="reference internal" href="#poltofloatexpr">\PolToFloatExpr</a></li>
+<li><a class="reference internal" href="#poltoexproneterm">\PolToExprOneTerm</a></li>
+<li><a class="reference internal" href="#poltofloatexproneterm">\PolToFloatExprOneTerm</a></li>
+<li><a class="reference internal" href="#poltoexprcmd">\PolToExprCmd</a></li>
+<li><a class="reference internal" href="#id33">\PolToFloatExprCmd</a></li>
+<li><a class="reference internal" href="#poltoexprtermprefix">\PolToExprTermPrefix</a></li>
+<li><a class="reference internal" href="#poltoexprvar">\PolToExprVar</a></li>
+<li><a class="reference internal" href="#poltoexprtimes">\PolToExprTimes</a></li>
+</ul>
+</li>
+<li><p class="first">improvements:</p>
+<ul>
+<li><p class="first">documentation has a table of contents, internal hyperlinks,
+standardized signature notations and added explanations.</p>
+</li>
+<li><p class="first">one can do <tt class="docutils literal"><span class="pre">\PolLet{g}={f}</span></tt> or <tt class="docutils literal"><span class="pre">\PolLet{g}{f}</span></tt>.</p>
+</li>
+<li><p class="first"><tt class="docutils literal">\PolToExpr{f}</tt> is highly customizable.</p>
+</li>
+<li><p class="first"><a class="reference internal" href="#poldef">\poldef</a> and other defining macros prepare the polynomial
+functions for usage within <tt class="docutils literal">\xintthefloatexpr</tt> (or
+<tt class="docutils literal">\xintdeffloatvar</tt>). Coefficients are pre-rounded to the
+floating point precision. Indispensible for numerical algorithms,
+as exact fractions, even reduced, quickly become very big. See the
+documentation about how to use the exact polynomials also in
+floating point context.</p>
+<p><strong>Attention</strong>: this has been reverted at <tt class="docutils literal">0.4</tt>. The macro
+<a class="reference internal" href="#polgenfloatvariant">\PolGenFloatVariant</a> must be used for
+generation floating point polynomial functions.</p>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+<li><p class="first">v0.3.1 (2018/01/18)</p>
+<p>Fixes two typos in example code included in the documentation.</p>
+</li>
+<li><p class="first">v0.4 (2018/02/16)</p>
+<ul>
+<li><p class="first">bug fixes:</p>
+<ul class="simple">
+<li>when Euclidean division gave a zero remainder, the internal
+representation of this zero polynomial could be faulty; this
+could cause mysterious bugs in conjunction with other package
+macros such as <a class="reference internal" href="#polmapcoeffs">\PolMapCoeffs</a>.</li>
+<li><a class="reference internal" href="#polgcd">\PolGCD</a> was buggy in case of first polynomial being
+of lesser degree than the second one.</li>
+</ul>
+</li>
+<li><p class="first">breaking changes:</p>
+<ul>
+<li><p class="first">formerly <a class="reference internal" href="#polevalat">\PolEval{P}\At{foo}</a> allowed <tt class="docutils literal">foo</tt> to
+be an expression, which was transparently handled via
+<tt class="docutils literal">\xinttheexpr</tt>. Now, <tt class="docutils literal">foo</tt> must be a fraction (or a macro
+expanding to such) in the format acceptable by <tt class="docutils literal">xintfrac.sty</tt>
+macros. Use <a class="reference internal" href="#polevalatexpr">\PolEval{P}\AtExpr{foo}</a> for more
+general arguments using expression syntax. E.g., if <tt class="docutils literal">foo</tt> is the
+name of a variable known to <tt class="docutils literal">\xintexpr</tt>.</p>
+<p>The same holds for <a class="reference internal" href="#polevalreducedat">\PolEvalReduced</a>
+and <a class="reference internal" href="#polfloatevalat">\PolFloatEval</a>.</p>
+</li>
+<li><p class="first">the <tt class="docutils literal">3.0</tt> automatic generation of floating point variants has
+been reverted. Not only do <em>not</em> the package macros automatically
+generate floating point variants of newly created polynomials,
+they actually make pre-existing such variant undefined.</p>
+<p>See <a class="reference internal" href="#polgenfloatvariant">\PolGenFloatVariant</a>.</p>
+</li>
+</ul>
+</li>
+<li><p class="first">new non-expandable macros:</p>
+<ul class="simple">
+<li><a class="reference internal" href="#polgenfloatvariant">\PolGenFloatVariant</a></li>
+<li><a class="reference internal" href="#polgloballet">\PolGlobalLet</a></li>
+<li><a class="reference internal" href="#poltypesetone">\PolTypesetOne</a></li>
+<li><a class="reference internal" href="#polquo">\PolQuo</a></li>
+<li><a class="reference internal" href="#polrem">\PolRem</a></li>
+<li><a class="reference internal" href="#poltosturm">\PolToSturm</a></li>
+<li><a class="reference internal" href="#id9">\PolToSturm*</a></li>
+<li><a class="reference internal" href="#polsettosturmchainsignchangesat">\PolSetToSturmChainSignChangesAt</a></li>
+<li><a class="reference internal" href="#polsettonbofzeroswithin">\PolSetToNbOfZerosWithin</a></li>
+<li><a class="reference internal" href="#polsturmisolatezeros">\PolSturmIsolateZeros</a></li>
+<li><a class="reference internal" href="#polrefineinterval">\PolRefineInterval*</a></li>
+<li><a class="reference internal" href="#polrefineinterval-n">\PolRefineInterval[N]</a></li>
+<li><a class="reference internal" href="#polensureintervallength">\PolEnsureIntervalLength</a></li>
+<li><a class="reference internal" href="#polensureintervallengths">\PolEnsureIntervalLengths</a></li>
+<li><a class="reference internal" href="#polprintintervals">\PolPrintIntervals</a></li>
+<li><a class="reference internal" href="#polprintintervalsprintexactzero">\PolPrintIntervalsPrintExactZero</a></li>
+<li><a class="reference internal" href="#polprintintervalsprintleftendpoint">\PolPrintIntervalsPrintLeftEndPoint</a></li>
+<li><a class="reference internal" href="#polprintintervalsprintrightendpoint">\PolPrintIntervalsPrintRightEndPoint</a></li>
+<li><a class="reference internal" href="#id20">\PolReduceCoeffs*</a></li>
+<li><a class="reference internal" href="#polmakemonic">\PolMakeMonic</a></li>
+</ul>
+</li>
+<li><p class="first">new expandable macros:</p>
+<ul class="simple">
+<li><a class="reference internal" href="#poltoexpronetermstylea">\PolToExprOneTermStyleA</a></li>
+<li><a class="reference internal" href="#polifcoeffisplusorminusone">\PolIfCoeffIsPlusOrMinusOne</a></li>
+<li><a class="reference internal" href="#polleadingcoeff">\PolLeadingCoeff</a></li>
+<li><a class="reference internal" href="#polsturmchainlength">\PolSturmChainLength</a></li>
+<li><a class="reference internal" href="#polsturmnbofisolatedzeros">\PolSturmNbOfIsolatedZeros</a></li>
+<li><a class="reference internal" href="#polsturmifzeroexactlyknown">\PolSturmIfZeroExactlyKnown</a></li>
+<li><a class="reference internal" href="#polsturmisolatedzeroleft">\PolSturmIsolatedZeroLeft</a></li>
+<li><a class="reference internal" href="#polsturmisolatedzeroright">\PolSturmIsolatedZeroRight</a></li>
+<li><tt class="docutils literal">\PolPrintIntervalsTheEndPoint</tt> (removed at 0.7)</li>
+<li><a class="reference internal" href="#polprintintervalstheindex">\PolPrintIntervalsTheIndex</a></li>
+<li><tt class="docutils literal">\PolIfEndPointIsPositive</tt> (removed at 0.7)</li>
+<li><tt class="docutils literal">\PolIfEndPointIsNegative</tt> (removed at 0.7)</li>
+<li><tt class="docutils literal">\PolIfEndPointIsZero</tt> (removed at 0.7)</li>
+<li><a class="reference internal" href="#polintervalwidth">\PolIntervalWidth</a></li>
+<li><a class="reference internal" href="#poldectostring">\PolDecToString</a></li>
+</ul>
+</li>
+<li><p class="first">improvements:</p>
+<p>The main new feature is implementation of the <a class="reference external" href="https://en.wikipedia.org/wiki/Sturm%27s_theorem">Sturm algorithm</a>
+for localization of the real roots of polynomials.</p>
+</li>
+</ul>
+</li>
+<li><p class="first">v0.4.1 (2018/03/01)</p>
+<p>Synced with xint 1.3.</p>
+</li>
+<li><p class="first">v0.4.2 (2018/03/03)</p>
+<p>Documentation fix.</p>
+</li>
+<li><p class="first">v0.5 (2018/04/08)</p>
+<ul class="simple">
+<li>bug fixes:<ul>
+<li><a class="reference internal" href="#polget-polname-fromarray-macro">\PolGet{polname}\fromarray\macro</a> crashed when <tt class="docutils literal">\macro</tt> was
+an <a class="reference external" href="http://www.ctan.org/pkg/xint">xinttools</a> array macro with no items. It now produces the zero
+polynomial.</li>
+</ul>
+</li>
+<li>breaking changes:<ul>
+<li><a class="reference internal" href="#poltosturm">\PolToSturm</a> creates primitive integer coefficients polynomials.
+This speeds up localization of roots via
+<a class="reference internal" href="#polsturmisolatezeros">\PolSturmIsolateZeros</a>. In case of user protests the author
+will make available again the code producing the bona fide Sturm
+polynomials as used formerly.</li>
+<li>polynomials created from <a class="reference internal" href="#polfromcsv">\PolFromCSV</a> or <a class="reference internal" href="#polget">\PolGet</a>
+get their coefficients normalized via <a class="reference external" href="http://www.ctan.org/pkg/xint">xintfrac</a>'s <tt class="docutils literal">\xintRaw</tt>.</li>
+</ul>
+</li>
+<li>experimental change:<ul>
+<li>optional argument to <a class="reference internal" href="#polsturmisolatezeros">\PolSturmIsolateZeros</a> (see <a class="reference internal" href="#the-degree-41-polynomial-with-2-1-9-1-8-0-0-1-1-9-2-as-roots">The
+degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., 1.9, 2
+as roots</a> for usage). It will presumably be replaced in future by
+an interval specification.</li>
+</ul>
+</li>
+<li>new non-expandable macro:<ul>
+<li><a class="reference internal" href="#polmakeprimitive">\PolMakePrimitive</a></li>
+</ul>
+</li>
+<li>new expandable macro:<ul>
+<li><a class="reference internal" href="#policontent">\PolIContent</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li><p class="first">v0.5.1 (2018/04/22)</p>
+<ul class="simple">
+<li>new feature:<ul>
+<li>the character <tt class="docutils literal">'</tt> can be used in polynomial names.</li>
+</ul>
+</li>
+</ul>
+</li>
+<li><p class="first">v0.6 (2018/11/20)</p>
+<ul class="simple">
+<li>bugfix:<ul>
+<li>the starred variant <a class="reference internal" href="#id10">\PolToSturm*{polname}{sturmname}</a> was
+broken. On the occasion of the fix, its meaning has been modified,
+see its documentation.</li>
+<li>using <a class="reference internal" href="#poltosturm">\PolToSturm</a> with a constant polynomial
+caused a division by zero error.</li>
+</ul>
+</li>
+<li>new macro:<ul>
+<li><a class="reference internal" href="#id11">\PolSturmIsolateZeros*</a>
+acts like the <a class="reference internal" href="#polsturmisolatezeros">non-starred variant</a> then computes all the multiplicities.</li>
+</ul>
+</li>
+<li>new expandable macros:<ul>
+<li><a class="reference internal" href="#polsturmisolatedzeromultiplicity-sturmname-index">\PolSturmIsolatedZeroMultiplicity{sturmname}{index}</a></li>
+<li><a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequalto-value">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}</a></li>
+<li><a class="reference internal" href="#polsturmnbofrootsof-sturmname-lessthanorequaltoexpr-expression">\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</a></li>
+<li><a class="reference internal" href="#polsturmnbwithmultofrootsof-sturmname-lessthanorequalto-value">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualTo{value}</a></li>
+<li><a class="reference internal" href="#polsturmnbwithmultofrootsof-sturmname-lessthanorequaltoexpr-expression">\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li><p class="first">v0.7 (2018/12/08), v0.7.1 (bugfix), v0.7.2 (2nd bugfix) (2018/12/09)</p>
+<ul class="simple">
+<li>breaking changes:<ul>
+<li>although <a class="reference internal" href="#polprintintervals-varname-sturmname">\PolPrintIntervals[varname]{sturmname}</a> default output
+remains the same, some auxiliary macros for user-customization
+have been removed: <tt class="docutils literal">\PolPrintIntervalsTheEndPoint</tt>,
+<tt class="docutils literal"><span class="pre">\PolIfEndPointIsPositive{A}{B}</span></tt>,
+<tt class="docutils literal"><span class="pre">\PolIfEndPointIsNegative{A}{B}</span></tt>, and
+<tt class="docutils literal"><span class="pre">\PolIfEndPointIsZero{A}{B}</span></tt>.</li>
+</ul>
+</li>
+<li>bugfix:<ul>
+<li>it could happen that, contrarily to documentation, an interval
+computed by <a class="reference internal" href="#polsturmisolatezeros-sturmname">\PolSturmIsolateZeros{sturmname}</a> had zero as an
+endpoint,</li>
+<li><a class="reference internal" href="#polensureintervallength-sturmname-index-e">\PolEnsureIntervalLength{sturmname}{index}{E}</a> could under
+certain circumstances erroneously replace a non-zero root by
+zero,</li>
+<li><a class="reference internal" href="#polensureintervallengths-sturmname-e">\PolEnsureIntervalLengths{sturmname}{E}</a> crashed when used with
+a polynomial with no real roots, hence for which no isolation intervals
+existed (thanks to Thomas Söll for report).</li>
+</ul>
+</li>
+<li>new macros:<ul>
+<li><a class="reference internal" href="#id14">\PolSturmIsolateZeros**{sturmname}</a></li>
+<li><a class="reference internal" href="#polsturmisolatezerosgetmultiplicitiesandrationalroots-sturmname">\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{sturmname}</a></li>
+<li><a class="reference internal" href="#polsturmisolatezerosandfindrationalroots-sturmname">\PolSturmIsolateZerosAndFindRationalRoots{sturmname}</a></li>
+<li><a class="reference internal" href="#polexprsetup">\polexprsetup</a></li>
+<li><a class="reference internal" href="#id18">\PolPrintIntervals*</a></li>
+<li><a class="reference internal" href="#polprintintervalsnorealroots">\PolPrintIntervalsNoRealRoots</a></li>
+<li><a class="reference internal" href="#polprintintervalsbeginenv">\PolPrintIntervalsBeginEnv</a></li>
+<li><a class="reference internal" href="#polprintintervalsendenv">\PolPrintIntervalsEndEnv</a></li>
+<li><a class="reference internal" href="#polprintintervalsknownroot">\PolPrintIntervalsKnownRoot</a></li>
+<li><a class="reference internal" href="#polprintintervalsunknownroot">\PolPrintIntervalsUnknownRoot</a></li>
+<li><a class="reference internal" href="#polprintintervalsprintmultiplicity">\PolPrintIntervalsPrintMultiplicity</a></li>
+</ul>
+</li>
+<li>new expandable macros:<ul>
+<li><a class="reference internal" href="#polsturmnbofrationalroots-sturmname">\PolSturmNbOfRationalRoots{sturmname}</a></li>
+<li><a class="reference internal" href="#polsturmnbofrationalrootswithmultiplicities-sturmname">\PolSturmNbOfRationalRootsWithMultiplicities{sturmname}</a></li>
+<li><a class="reference internal" href="#polsturmrationalroot-sturmname-k">\PolSturmRationalRoot{sturmname}{k}</a></li>
+<li><a class="reference internal" href="#polsturmrationalrootindex-sturmname-k">\PolSturmRationalRootIndex{sturmname}{k}</a></li>
+<li><a class="reference internal" href="#polsturmrationalrootmultiplicity-sturmname-k">\PolSturmRationalRootMultiplicity{sturmname}{k}</a></li>
+<li><a class="reference internal" href="#polprintintervalsthevar">\PolPrintIntervalsTheVar</a></li>
+<li><a class="reference internal" href="#polprintintervalsthesturmname">\PolPrintIntervalsTheSturmName</a></li>
+<li><a class="reference internal" href="#polprintintervalsthemultiplicity">\PolPrintIntervalsTheMultiplicity</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li><p class="first">v0.7.3 (2019/02/04)</p>
+<ul class="simple">
+<li>bugfix:<ul>
+<li>Debugging information not destined to user showed in log if root
+finding was done under <tt class="docutils literal">\xintverbosetrue</tt> regime.</li>
+<li><a class="reference internal" href="#polprintintervalsthevar">\PolPrintIntervalsTheVar</a> remained defined after
+<a class="reference internal" href="#polprintintervals">\PolPrintIntervals</a> but was left undefined after
+<a class="reference internal" href="#id18">\PolPrintIntervals*</a> (reported by Jürgen Gilg). Now remains
+defined in both cases, and <a class="reference internal" href="#polprintintervalsthesturmname">\PolPrintIntervalsTheSturmName</a>
+also.</li>
+<li>Polynomial names ending in digits caused errors (reported by Thomas
+Söll).</li>
+</ul>
+</li>
+</ul>
+</li>
+<li><p class="first">v0.7.4 (2019/02/12)</p>
+<ul class="simple">
+<li>bugfix:<ul>
+<li>20000000000 is too big for <tt class="docutils literal">\numexpr</tt>, shouldn't I know that?
+Thanks to Jürgen Gilg for report.</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</div>
+<div class="section" id="acknowledgments">
+<h1><a class="toc-backref" href="#id160">Acknowledgments</a></h1>
+<p>Thanks to Jürgen Gilg whose question about <a class="reference external" href="http://www.ctan.org/pkg/xint">xint</a> usage for
+differentiating polynomials was the initial trigger leading to this
+package, and to Jürgen Gilg and Thomas Söll for testing it on some
+concrete problems.</p>
+<p>Renewed thanks to them on occasion of the <tt class="docutils literal">0.6</tt> and <tt class="docutils literal">0.7</tt> releases for their
+continued interest.</p>
+<p>See README.md for the License.</p>
+</div>
+</div>
+</body>
+</html>
diff --git a/macros/latex/contrib/polexpr/polexpr.sty b/macros/latex/contrib/polexpr/polexpr.sty
new file mode 100644
index 0000000000..e9509d8942
--- /dev/null
+++ b/macros/latex/contrib/polexpr/polexpr.sty
@@ -0,0 +1,2946 @@
+% author: Jean-François Burnol
+% License: LPPL 1.3c (author-maintained)
+\ProvidesPackage{polexpr}%
+ [2019/02/12 v0.7.4 Polynomial expressions with rational coefficients (JFB)]%
+\RequirePackage{xintexpr}[2018/06/17]% xint 1.3c for \ifxintglobaldefs boolean
+\edef\POL@restorecatcodes
+ {\catcode`\noexpand\_ \the\catcode`\_ %
+ \catcode`\noexpand\! \the\catcode`\! %
+ \catcode`\noexpand\* \the\catcode`\* %
+ \catcode0 \the\catcode0\relax}%
+\catcode`\_ 11 \catcode0 12 \catcode`\* 12
+\long\def\xint_stop_atfirstoftwo #1#2{ #1}% not yet in xint 1.3c
+\long\def\xint_stop_atsecondoftwo #1#2{ #2}%
+
+%% PATCH xintexpr TO AUTHORIZE ' IN NAMES (0.5.1)
+\catcode`\! 11
+\def\POL@XINT_expr_scanfunc_b #1%
+{%
+ \ifx !#1\xint_dothis{(_}\fi
+ \ifcat \relax#1\xint_dothis{(_}\fi
+ \if (#1\xint_dothis{\xint_firstoftwo{(`}}\fi
+ \if '#1\xint_dothis \XINT_expr_scanfunc_a \fi
+ \if @#1\xint_dothis \XINT_expr_scanfunc_a \fi
+ \if _#1\xint_dothis \XINT_expr_scanfunc_a \fi
+ \ifnum \xint_c_ix<1\string#1 \xint_dothis \XINT_expr_scanfunc_a \fi
+ \ifcat a#1\xint_dothis \XINT_expr_scanfunc_a \fi
+ \xint_orthat {(_}%
+ #1%
+}%
+
+%% AUXILIARIES
+\catcode`! 3
+%% added at 0.7
+\newcommand\polexprsetup[1]{\POL@setup_parsekeys #1,=!,\xint_bye}%
+\def\POL@setup_parsekeys #1=#2#3,{%
+ \ifx!#2\expandafter\xint_bye\fi
+ \csname POL@setup_setkey_\xint_zapspaces #1 \xint_gobble_i\endcsname
+ \xint_firstoftwo
+ {\PackageWarning{polexpr}{The \detokenize{#1} key is unknown! ignoring}}%
+ {\xintZapLastSpaces{#2#3}}%
+ \POL@setup_parsekeys
+}%
+\catcode`! 11
+\def\POL@setup_setkey_norr #1#2{\edef\POL@norr}%
+\def\POL@setup_setkey_sqfnorr #1#2{\edef\POL@sqfnorr}%
+\polexprsetup{norr=_norr, sqfnorr=_sqf_norr}
+
+\newcount\POL@count
+\newif\ifPOL@pol
+\newif\ifxintveryverbose
+\newif\ifpoltypesetall
+\newif\ifPOL@tosturm@makefirstprimitive
+\POL@tosturm@makefirstprimitivetrue
+\newif\ifPOL@isolz@nextwillneedrefine
+\newif\ifpoltoexprall
+%% the main exchange structure (stored in macros \POLuserpol@<name>)
+%% is: degree.\empty{coeff0}{coeff1}....{coeffN}
+%% (degree=N except zero polynomial recognized from degree set to -1
+%% but it has always the {0/1[0]} coeff0.)
+\def\POL@ifZero#1{\expandafter\POL@ifZero@aux#1;}%
+\def\POL@ifZero@aux #1#2;{\if-#1\expandafter\xint_firstoftwo
+ \else\expandafter\xint_secondoftwo
+ \fi}%
+\def\POL@split#1.#2;#3#4% separates degree and list of coefficients
+% The \expandafter chain removes the \empty token
+ {\def#3{#1}\expandafter\def\expandafter#4\expandafter{#2}}%
+%
+\def\POL@resultfromarray #1{% ATTENTION, **MUST** be executed with
+% \count@ set to 1 + degree (\count@ = 0 for zero polynomial)
+ \edef\POL@result{\ifnum\count@>\z@
+ \the\numexpr\count@-\@ne.\noexpand\empty
+ \xintiloop [1+1]%
+ \expandafter\POL@braceit\csname POL@array#1\xintiloopindex\endcsname
+ \ifnum\xintiloopindex<\count@
+ \repeat
+ \else-1.\noexpand\empty{0/1[0]}\fi}%
+}%
+\def\POL@braceit#1{{#1}}% needed as \xintiloopindex can not "see" through braces
+
+
+\newcommand\PolDef[3][x]{\poldef #2(#1):=#3;}%
+\def\poldef{\edef\POL@restoresemicolon{\catcode59=\the\catcode59\relax}%
+ \catcode59 12 \POL@defpol}%
+\def\POL@defpol #1(#2)#3=#4;{%
+ \POL@restoresemicolon
+ \edef\POL@tmp{\ifxintverbose1\else0\fi}%
+ \unless\ifxintveryverbose\xintverbosefalse\fi
+ \let\POL@originalXINT_expr_scanfunc_b\XINT_expr_scanfunc_b
+ \let\XINT_expr_scanfunc_b\POL@XINT_expr_scanfunc_b
+ \xintdeffunc __pol(#2):=0+(#4);% force conversion to raw if a constant
+ \if1\POL@tmp\xintverbosetrue\fi
+ \edef\POL@polname{\xint_zapspaces #1 \xint_gobble_i}%
+ \let\XINT_expr_scanfunc_b\POL@originalXINT_expr_scanfunc_b
+ \begingroup
+ \setbox0\hbox{%
+ \let\xintScalarAdd\xintAdd
+ \let\xintScalarSub\xintSub
+ \let\xintScalarMul\xintMul
+ \let\xintScalarDiv\xintDiv
+ \let\xintScalarPow\xintPow
+ \let\xintScalarOpp\xintOpp
+ \let\xintAdd\POL@add
+ \let\xintMul\POL@mul
+ \let\xintDiv\POL@div
+ \let\xintPow\POL@pow
+ \let\xintOpp\POL@opp
+ \def\xintSub ##1##2{\xintAdd{##1}{\xintOpp{##2}}}%
+ % \xintAdd{0} to get \POL@result defined even if numerical only expression
+ % I could also test \ifPOL@pol, but this is anyhow small overhead
+ \xintAdd{0}%
+ {\csname XINT_expr_userfunc___pol\endcsname
+ {\global\POL@poltrue\def\POL@result{1.\empty{0/1[0]}{1/1[0]}}}}%
+ \expandafter}\expandafter
+ \endgroup\expandafter
+ \def\csname POLuserpol@\POL@polname\expandafter\endcsname
+ \expandafter{\POL@result}%
+ \expandafter\POL@newpol\expandafter{\POL@polname}%
+}%
+%%
+\def\POL@newpol#1{%
+ \expandafter\POL@ifZero\csname POLuserpol@#1\endcsname
+ {\@namedef{XINT_expr_userfunc_#1}##1{0/1[0]}}%
+ {\POL@newpolhorner{#1}}%
+ \expandafter\XINT_expr_defuserfunc
+ \csname XINT_expr_func_#1\endcsname{#1}{expr}%
+ \expandafter\let\csname XINT_flexpr_func_#1\endcsname\@undefined
+ \ifxintverbose\POL@info{#1}\fi
+}%
+\def\POL@newfloatpol#1{%
+ \expandafter\POL@ifZero\csname POLuserpol@#1\endcsname
+ {\@namedef{XINT_flexpr_userfunc_#1}##1{0[0]}}%
+ {\POL@newfloatpolhorner{#1}}%
+ \expandafter\XINT_expr_defuserfunc
+ \csname XINT_flexpr_func_#1\endcsname{#1}{flexpr}%
+ \ifxintverbose\POL@floatinfo{#1}\fi
+}%
+\def\POL@info #1{%
+ \xintMessage {polexpr}{Info}%
+ {Function #1 for the \string\xintexpr\space parser is
+ associated to \string\XINT_expr_userfunc_#1\space
+ whose meaning uses Horner scheme:
+ \expandafter\meaning
+ \csname XINT_expr_userfunc_#1\endcsname}%
+}%
+\def\POL@floatinfo #1{%
+ \xintMessage {polexpr}{Info}%
+ {Function #1 for the \string\xintfloatexpr\space parser is
+ associated to \string\XINT_flexpr_userfunc_#1\space
+ whose meaning uses Horner scheme:
+ \expandafter\meaning
+ \csname XINT_flexpr_userfunc_#1\endcsname}%
+}%
+%
+\def\POL@newpolhorner#1{%
+ %% redefine function to expand by Horner scheme. Is this useful?
+ %% perhaps bad idea for numerical evaluation of thing such as (1+x)^10?
+% note: I added {0/1[0]} item to zero polynomial also to facilitate this
+ \expandafter\expandafter\expandafter\POL@split
+ \csname POLuserpol@#1\endcsname;\POL@var@deg\POL@var@coeffs
+ \edef\POL@var@coeffs{\xintRevWithBraces{\POL@var@coeffs}}%
+ \begingroup
+ \expandafter\POL@newpol@horner\POL@var@coeffs\relax
+ \expandafter
+ \endgroup
+ \expandafter\def\csname XINT_expr_userfunc_#1\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter{\POL@tmp{##1}}%
+}%
+\def\POL@newfloatpolhorner#1{%
+ %% redefine function to expand by Horner scheme. Is this useful?
+ %% perhaps bad idea for numerical evaluation of thing such as (1+x)^10?
+% note: I added {0/1[0]} item to zero polynomial also to facilitate this
+ \expandafter\expandafter\expandafter\POL@split
+ \csname POLuserpol@#1\endcsname;\POL@var@deg\POL@var@coeffs
+ \edef\POL@var@coeffs{\xintRevWithBraces{\POL@var@coeffs}}%
+ \begingroup
+ \expandafter\POL@newpol@floathorner\POL@var@coeffs\relax
+ \expandafter
+ \endgroup
+ \expandafter\def\csname XINT_flexpr_userfunc_#1\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter{\POL@tmp{##1}}%
+}%
+\def\POL@newpol@horner#1{\let\xintAdd\relax\let\xintMul\relax
+ \def\POL@tmp##1{#1}\POL@newpol@horner@loop.}%
+\def\POL@newpol@horner@loop.#1{%
+ \if\relax#1\expandafter\xint_gob_til_dot\fi
+ \edef\POL@tmp##1{\xintiiifZero{#1}
+ {\@firstofone}{\xintAdd{#1}}%
+ {\xintMul{##1}{\POL@tmp{##1}}}}%
+ \POL@newpol@horner@loop.%
+}%
+\def\POL@newpol@floathorner#1{\let\XINTinFloatAdd\relax\let\XINTinFloatMul\relax
+ \def\xintAdd{\XINTinFloatAdd}\def\xintMul{\XINTinFloatMul}%
+ \edef\POL@tmp##1{\XINTinFloatdigits{#1}}%
+ \POL@newpol@floathorner@loop.}%
+\def\POL@newpol@floathorner@loop.#1{%
+ \if\relax#1\expandafter\xint_gob_til_dot\fi
+ \edef\POL@tmp##1{\xintiiifZero{#1}
+ {\@firstofone}{\xintAdd{\XINTinFloatdigits{#1}}}%
+ {\xintMul{##1}{\POL@tmp{##1}}}}%
+ \POL@newpol@floathorner@loop.%
+}%
+
+
+\newcommand\PolGenFloatVariant[1]{\POL@newfloatpol{#1}}%
+
+
+\newcommand\PolLet[2]{\if=\noexpand#2\expandafter\xint_firstoftwo
+ \else\expandafter\xint_secondoftwo\fi
+ \POL@@let\POL@let{#1}{#2}}%
+\def\POL@@let#1#2#3{\POL@let{#1}{#3}}%
+\def\POL@let#1#2{%
+ \expandafter\let\csname POLuserpol@#1\expandafter\endcsname
+ \csname POLuserpol@#2\endcsname
+ \expandafter\let\csname XINT_expr_userfunc_#1\expandafter\endcsname
+ \csname XINT_expr_userfunc_#2\endcsname
+ \expandafter\XINT_expr_defuserfunc
+ \csname XINT_expr_func_#1\endcsname{#1}{expr}%
+ \ifxintverbose\POL@info{#1}\fi
+}%
+\newcommand\PolGlobalLet[2]{\begingroup
+ \globaldefs\@ne
+ \if=\noexpand#2\expandafter\xint_firstoftwo
+ \else\expandafter\xint_secondoftwo\fi
+% do I need to check something here relative to \xintNewExpr?
+ \POL@@globallet\POL@globallet {#1}{#2}}%
+\def\POL@@globallet#1#2#3{\POL@globallet{#1}{#3}}%
+\def\POL@globallet#1#2{\POL@let{#1}{#2}\endgroup}%
+
+\newcommand\PolAssign[1]{\def\POL@polname{#1}\POL@assign}% zap spaces in #1?
+\def\POL@assign#1\toarray#2{%
+ \expandafter\expandafter\expandafter\POL@split
+ \csname POLuserpol@\POL@polname\endcsname;\POL@var@deg\POL@var@coeffs
+ \xintAssignArray\POL@var@coeffs\to#2%
+ % modify \#200 macro to return 0/1[0] for out of range indices
+ \@namedef{\xint_arrayname00}##1##2##3{%
+ \@namedef{\xint_arrayname00}####1{%
+ \ifnum####1>##1 \xint_dothis{ 0/1[0]}\fi
+ \ifnum####1>\m@ne \xint_dothis
+ {\expandafter\expandafter\expandafter##3%
+ \csname##2####1\endcsname}\fi
+ \unless\ifnum-####1>##1 \xint_dothis
+ {\expandafter\expandafter\expandafter##3%
+ \csname##2\the\numexpr##1+####1+\@ne\endcsname}\fi
+ \xint_orthat{ 0/1[0]}}% space stops a \romannumeral0
+ }%
+ \csname\xint_arrayname00\expandafter\expandafter\expandafter\endcsname
+ \expandafter\expandafter\expandafter
+ {\csname\xint_arrayname0\expandafter\endcsname\expandafter}\expandafter
+ {\xint_arrayname}{ }%
+}%
+
+
+\newcommand\PolGet{}%
+\def\PolGet#1#2\fromarray#3{%
+ \begingroup % closed in \POL@getfromarray
+ \POL@getfromarray{#1}{#3}%
+ \POL@newpol{#1}%
+}%
+\def\POL@getfromarray#1#2{%
+ \count@=#2{0} %<- intentional space
+ \ifnum\count@=\z@
+ \def\POL@result{-1.\empty{0/1[0]}}% 0.5 fix for empty array
+ \else
+ \xintloop
+ \edef\POL@tmp{#2{\count@}}%
+ \edef\POL@tmp{\xintRaw{\POL@tmp}}%
+% sadly xinttools (current 1.3a) arrays have no setters for individual items...
+ \expandafter\let\csname POL@tmparray\the\count@\endcsname\POL@tmp
+ \if0\xintiiSgn{\POL@tmp}%
+ \advance\count@\m@ne
+ \repeat
+% dans le cas particulier d'un array avec que des éléments nuls, \count@ est
+% ici devenu 0 et la boucle s'est arrêtée car #2{0} était au moins 1. De plus
+% \POL@tmparray1 est bien 0/1[0] donc ok pour polynôme nul dans \POL@result
+ \count\tw@\count@
+ \xintloop
+% on mouline tous les coeffs via \xintRaw
+ \ifnum\count@>\@ne
+ \advance\count@\m@ne
+ \edef\POL@tmp{#2{\count@}}%
+ \edef\POL@tmp{\xintRaw{\POL@tmp}}%
+ \expandafter\let\csname POL@tmparray\the\count@\endcsname\POL@tmp
+ \repeat
+ \count@\count\tw@
+ \def\POL@tmp##1.{{\csname POL@tmparray##1\endcsname}}%
+ \edef\POL@result{\the\numexpr\count@-\@ne.\noexpand\empty
+ \xintiloop[1+1]%
+ \expandafter\POL@tmp\xintiloopindex.%
+ \ifnum\xintiloopindex<\count@
+ \repeat}%
+ \fi
+ \expandafter
+ \endgroup
+ \expandafter
+ \def\csname POLuserpol@#1\expandafter\endcsname
+ \expandafter{\POL@result}%
+}%
+
+
+\newcommand\PolFromCSV[2]{%
+ \begingroup % closed in \POL@getfromarray
+ \xintAssignArray\xintCSVtoList{#2}\to\POL@arrayA
+ \POL@getfromarray{#1}\POL@arrayA
+ \POL@newpol{#1}%
+% semble un peu indirect et sous-optimal
+% mais je veux élaguer les coefficients nuls. Peut-être à revoir.
+}%
+
+
+\newcommand\PolTypesetCmdPrefix[1]{\xintiiifSgn{#1}{}{+}{+}}%
+\newcommand\PolTypesetCmd[1]{\xintifOne{\xintiiAbs{#1}}%
+ {\ifnum\PolIndex=\z@\xintiiSgn{#1}\else
+ \xintiiifSgn{#1}{-}{}{}\fi
+ \let\PolIfCoeffIsPlusOrMinusOne\@firstoftwo}%
+ {\PolTypesetOne{#1}%
+ \let\PolIfCoeffIsPlusOrMinusOne\@secondoftwo}%
+ }%
+\newcommand\PolTypesetOne{\xintSignedFrac}%
+\newcommand\PolTypesetMonomialCmd{%
+ \ifcase\PolIndex\space
+ %
+ \or\PolVar
+ \else\PolVar^{\PolIndex}%
+ \fi
+}%
+\newcommand\PolTypeset{\@ifstar
+ {\def\POL@ts@ascending{1}\POL@Typeset}%
+ {\def\POL@ts@ascending{0}\POL@Typeset}%
+}%
+\newcommand\POL@Typeset[2][x]{% LaTeX \newcommand forces optional argument first
+ \ensuremath{%
+ \expandafter\expandafter\expandafter\POL@split
+ \csname POLuserpol@#2\endcsname;\POL@var@deg\POL@var@coeffs
+ \if\POL@ts@ascending1%
+ \def\PolIndex{0}%
+ \let\POL@ts@reverse\@firstofone
+ \let\POL@@ne@or@m@ne\@ne
+ \else
+ \let\PolIndex\POL@var@deg
+ \ifnum\PolIndex<\z@\def\PolIndex{0}\fi
+ \let\POL@ts@reverse\xintRevWithBraces
+ \let\POL@@ne@or@m@ne\m@ne
+ \fi
+ \def\PolVar{#1}%
+ \ifnum\POL@var@deg<\z@
+ \PolTypesetCmd{0/1[0]}\PolTypesetMonomialCmd
+ \else
+ \ifnum\POL@var@deg=\z@
+ \expandafter\PolTypesetCmd\POL@var@coeffs\PolTypesetMonomialCmd
+ \else
+ \def\POL@ts@prefix##1{\let\POL@ts@prefix\PolTypesetCmdPrefix}%
+ \expandafter\POL@ts@loop
+ \romannumeral-`0\POL@ts@reverse{\POL@var@coeffs}\relax
+ \fi
+ \fi
+ }%
+}%
+\def\POL@ts@loop{\ifpoltypesetall\expandafter\xint_firstoftwo
+ \else\expandafter\xint_secondoftwo\fi
+ {\POL@ts@nocheck}{\POL@ts@check}.%
+}%
+\def\POL@ts@check.#1{%
+ \if\relax#1\expandafter\xint_gob_til_dot\fi
+ \xintiiifZero{#1}%
+ {}%
+ {\POL@ts@prefix{#1}\PolTypesetCmd{#1}\PolTypesetMonomialCmd}%
+ \edef\PolIndex{\the\numexpr\PolIndex+\POL@@ne@or@m@ne}\POL@ts@check.%
+}%
+\def\POL@ts@nocheck.#1{%
+ \if\relax#1\expandafter\xint_gob_til_dot\fi
+ \POL@ts@prefix{#1}\PolTypesetCmd{#1}\PolTypesetMonomialCmd
+ \edef\PolIndex{\the\numexpr\PolIndex+\POL@@ne@or@m@ne}\POL@ts@nocheck.%
+}%
+
+
+\newcommand\PolMapCoeffs[2]{% #1 = macro, #2 = name
+ \POL@mapcoeffs{#1}{#2}%
+ \POL@newpol{#2}%
+}%
+\def\POL@mapcoeffs#1#2{%
+ \begingroup
+ \def\POL@mapcoeffs@macro{#1}%
+ \expandafter\expandafter\expandafter\POL@split
+ \csname POLuserpol@#2\endcsname;\POL@mapcoeffs@deg\POL@mapcoeffs@coeffs
+% ATTENTION à ne pas faire un \expandafter ici, car brace removal si 1 item
+ \xintAssignArray\POL@mapcoeffs@coeffs\to\POL@arrayA
+ \def\index{0}%
+ \count@\z@
+ \expandafter\POL@map@loop\expandafter.\POL@mapcoeffs@coeffs\relax
+ \xintloop
+% this abuses that \POL@arrayA0 is never 0.
+ \xintiiifZero{\csname POL@arrayA\the\count@\endcsname}%
+ {\iftrue}%
+ {\iffalse}%
+ \advance\count@\m@ne
+ \repeat
+% donc en sortie \count@ est 0 ssi pol nul.
+ \POL@resultfromarray A%
+ \expandafter
+ \endgroup
+ \expandafter
+ \def\csname POLuserpol@#2\expandafter\endcsname\expandafter{\POL@result}%
+}%
+\def\POL@map@loop.#1{\if\relax#1\expandafter\xint_gob_til_dot\fi
+ \advance\count@\@ne
+ \edef\POL@map@coeff{\POL@mapcoeffs@macro{#1}}%
+ \expandafter
+ \let\csname POL@arrayA\the\count@\endcsname\POL@map@coeff
+ \edef\index{\the\numexpr\index+\@ne}%
+ \POL@map@loop.}%
+\def\POL@xintIrr#1{\xintIrr{#1}[0]}%
+\newcommand\PolReduceCoeffs{\@ifstar\POL@sreducecoeffs\POL@reducecoeffs}%
+\def\POL@reducecoeffs#1{\PolMapCoeffs{\POL@xintIrr}{#1}}%
+\def\POL@sreducecoeffs#1{\PolMapCoeffs{\xintPIrr}{#1}}%
+
+
+%% EUCLIDEAN DIVISION
+\newcommand\PolDivide[4]{% #3=quotient, #4=remainder of #1 by #2
+ \POL@divide{#1}{#2}%
+ \expandafter\let\csname POLuserpol@#3\endcsname\POL@Q
+ \POL@newpol{#3}%
+ \expandafter\let\csname POLuserpol@#4\endcsname\POL@R
+ \POL@newpol{#4}%
+}%
+\newcommand\PolQuo[3]{% #3=quotient of #1 by #2
+ \POL@divide{#1}{#2}%
+ \expandafter\let\csname POLuserpol@#3\endcsname\POL@Q
+ \POL@newpol{#3}%
+}%
+\newcommand\PolRem[3]{% #3=remainder of #1 by #2
+ \POL@divide{#1}{#2}%
+ \expandafter\let\csname POLuserpol@#3\endcsname\POL@R
+ \POL@newpol{#3}%
+}%
+\newcommand\POL@divide[2]{%
+ \begingroup
+ \let\xintScalarSub\xintSub
+ \let\xintScalarAdd\xintAdd
+ \let\xintScalarMul\xintMul
+ \let\xintScalarDiv\xintDiv
+ \expandafter\let\expandafter\POL@A\csname POLuserpol@#1\endcsname
+ \expandafter\let\expandafter\POL@B\csname POLuserpol@#2\endcsname
+ \POL@div@c
+ \let\POL@Q\POL@result
+ \ifnum\POL@degQ<\z@
+ \let\POL@R\POL@A
+ \else
+ \count@\numexpr\POL@degR+\@ne\relax
+ \POL@resultfromarray R%
+ \let\POL@R\POL@result
+ \fi
+ \expandafter
+ \endgroup
+ \expandafter
+ \def\csname POL@Q\expandafter\expandafter\expandafter\endcsname
+ \expandafter\expandafter\expandafter{\expandafter\POL@Q\expandafter}%
+ \expandafter
+ \def\csname POL@R\expandafter\endcsname\expandafter{\POL@R}%
+}%
+
+
+%% GCD
+\newcommand\PolGCD[3]{% sets #3 to the (unitary) G.C.D. of #1 and #2
+ \POL@GCD{#1}{#2}{#3}%
+ \POL@newpol{#3}%
+}%
+\def\POL@GCD #1#2#3{%
+ \begingroup
+ \let\xintScalarSub\xintSub
+ \let\xintScalarAdd\xintAdd
+ \let\xintScalarMul\xintMul
+ \let\xintScalarDiv\xintDiv
+ \expandafter\let\expandafter\POL@A\csname POLuserpol@#1\endcsname
+ \expandafter\let\expandafter\POL@B\csname POLuserpol@#2\endcsname
+ \expandafter\POL@split\POL@A;\POL@degA\POL@polA
+ \expandafter\POL@split\POL@B;\POL@degB\POL@polB
+ \ifnum\POL@degA<\z@
+ \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo
+ \fi
+ {\ifnum\POL@degB<\z@
+ \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo
+ \fi
+ {\def\POL@result{-1.\empty{0/1[0]}}}%
+ {\xintAssignArray\POL@polB\to\POL@arrayB
+ \POL@normalize{B}%
+ \POL@gcd@exit BA}}%
+ {\ifnum\POL@degB<\z@
+ \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo
+ \fi
+ {\xintAssignArray\POL@polA\to\POL@arrayA
+ \POL@normalize{A}%
+ \POL@gcd@exit AB}%
+ {\ifnum\POL@degA<\POL@degB\space
+ \let\POL@tmp\POL@B\let\POL@B\POL@A\let\POL@A\POL@tmp
+ \let\POL@tmp\POL@degB\let\POL@degB\POL@degA\let\POL@degA\POL@tmp
+ \let\POL@tmp\POL@polB\let\POL@polB\POL@polA\let\POL@polA\POL@tmp
+ \fi
+ \xintAssignArray\POL@polA\to\POL@arrayA
+ \xintAssignArray\POL@polB\to\POL@arrayB
+ \POL@gcd AB%
+ }}%
+ \expandafter
+ \endgroup
+ \expandafter\def\csname POLuserpol@#3\expandafter\endcsname
+ \expandafter{\POL@result}%
+}%
+\def\POL@normalize#1{%
+ \expandafter\def\expandafter\POL@tmp\expandafter
+ {\csname POL@array#1\csname POL@array#10\endcsname\endcsname}%
+ \edef\POL@normalize@leading{\POL@tmp}%
+ \expandafter\def\POL@tmp{1/1[0]}%
+ \count@\csname POL@deg#1\endcsname\space
+ \xintloop
+ \ifnum\count@>\z@
+ \expandafter\edef\csname POL@array#1\the\count@\endcsname
+ {\xintIrr{\xintScalarDiv
+ {\csname POL@array#1\the\count@\endcsname}%
+ {\POL@normalize@leading}}[0]}%
+ \advance\count@\m@ne
+ \repeat
+}%
+\def\POL@gcd#1#2{%
+ \POL@normalize{#2}%
+ \edef\POL@degQ{\the\numexpr\csname POL@deg#1\endcsname
+ -\csname POL@deg#2\endcsname}%
+ \count@\numexpr\csname POL@deg#1\endcsname+\@ne\relax
+ \count\tw@\numexpr\POL@degQ+\@ne\relax
+ \xintloop
+ \POL@gcd@getremainder@loopbody#1#2%
+ \ifnum\count\tw@>\z@
+ \repeat
+ \expandafter\def\csname POL@array#10\endcsname{1}%
+ \xintloop
+ \xintiiifZero{\csname POL@array#1\the\count@\endcsname}%
+ {\iftrue}%
+ {\iffalse}%
+ \advance\count@\m@ne
+ \repeat
+ \expandafter\edef\csname POL@deg#1\endcsname{\the\numexpr\count@-\@ne}%
+ \ifnum\count@<\@ne
+ \expandafter\POL@gcd@exit
+ \else
+ \expandafter\edef\csname POL@array#10\endcsname{\the\count@}%
+ \expandafter\POL@gcd
+ \fi{#2}{#1}%
+}%
+\def\POL@gcd@getremainder@loopbody#1#2{%
+ \edef\POL@gcd@ratio{\csname POL@array#1\the\count@\endcsname}%
+ \advance\count@\m@ne
+ \advance\count\tw@\m@ne
+ \count4 \count@
+ \count6 \csname POL@deg#2\endcsname\space
+ \xintloop
+ \ifnum\count6>\z@
+ \expandafter\edef\csname POL@array#1\the\count4\endcsname
+ {\xintScalarSub
+ {\csname POL@array#1\the\count4\endcsname}%
+ {\xintScalarMul
+ {\POL@gcd@ratio}%
+ {\csname POL@array#2\the\count6\endcsname}}}%
+ \advance\count4 \m@ne
+ \advance\count6 \m@ne
+ \repeat
+}%
+\def\POL@gcd@exit#1#2{%
+ \count@\numexpr\csname POL@deg#1\endcsname+\@ne\relax
+ \POL@resultfromarray #1%
+}%
+
+
+%% TODO: BEZOUT
+
+
+%% DIFFERENTIATION
+\def\POL@diff@loop@one #1/#2[#3]#4%
+ {\xintIrr{\xintiiMul{#4}{#1}/#2[0]}[#3]}%
+\def\POL@diff#1{\POL@diff@loop1.}%
+\def\POL@diff@loop#1.#2{%
+ \if\relax#2\expandafter\xint_gob_til_dot\fi
+ {\expandafter\POL@diff@loop@one\romannumeral0\xintraw{#2}{#1}}%
+ \expandafter\POL@diff@loop\the\numexpr#1+\@ne.%
+}%
+\newcommand\PolDiff[1][1]{%
+ % optional parameter is how many times to derivate
+ % first mandatory arg is name of polynomial function to derivate,
+ % same name as in \NewPolExpr
+ % second mandatory arg name of derivative
+ \edef\POL@iterindex{\the\numexpr#1\relax}%
+ \ifnum\POL@iterindex<\z@
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ {\PolAntiDiff[-\POL@iterindex]}{\POL@Diff}%
+}%
+\def\POL@Diff{%
+ \ifcase\POL@iterindex\space
+ \expandafter\POL@Diff@no
+ \or\expandafter\POL@Diff@one
+ \else\xint_afterfi{\POL@Iterate\POL@Diff@one}%
+ \fi
+}%
+\def\POL@Diff@no #1#2{\POL@let{#2}{#1}}%
+\def\POL@Diff@one #1#2{\POL@Diff@@one {#1}{#2}\POL@newpol{#2}}%
+\def\POL@Diff@@one#1#2{%
+ \expandafter\expandafter\expandafter\POL@split
+ \csname POLuserpol@#1\endcsname;\POL@var@deg\POL@var@coeffs
+ \ifnum\POL@var@deg<\@ne
+ \@namedef{POLuserpol@#2}{-1.\empty{0/1[0]}}%
+ \else
+ \edef\POL@var@coeffs{\expandafter\POL@diff\POL@var@coeffs\relax}%
+ \expandafter\edef\csname POLuserpol@#2\endcsname
+ {\the\numexpr\POL@var@deg-\@ne.\noexpand\empty\POL@var@coeffs}%
+ \fi
+}%
+% lazy way but allows to share with AntiDiff
+\def\POL@Iterate#1#2#3{%
+ \begingroup
+ \xintverbosefalse
+ #1{#2}{#3}%
+ \xintloop
+ \ifnum\POL@iterindex>\tw@
+ #1{#3}{#3}%
+ \edef\POL@iterindex{\the\numexpr\POL@iterindex-\@ne}%
+ \repeat
+ \expandafter
+ \endgroup\expandafter
+ \def\csname POLuserpol@#3\expandafter\endcsname
+ \expandafter{\romannumeral`^^@\csname POLuserpol@#3\endcsname}%
+ #1{#3}{#3}%
+}%
+
+
+%% ANTI-DIFFERENTIATION
+\def\POL@antidiff@loop@one #1/#2[#3]#4%
+ {\xintIrr{#1/\xintiiMul{#4}{#2}[0]}[#3]}%
+\def\POL@antidiff{\POL@antidiff@loop1.}%
+\def\POL@antidiff@loop#1.#2{%
+ \if\relax#2\expandafter\xint_gob_til_dot\fi
+ {\expandafter\POL@antidiff@loop@one\romannumeral0\xintraw{#2}{#1}}%
+ \expandafter\POL@antidiff@loop\the\numexpr#1+\@ne.%
+}%
+\newcommand\PolAntiDiff[1][1]{%
+ % optional parameter is how many times to derivate
+ % first mandatory arg is name of polynomial function to derivate,
+ % same name as in \NewPolExpr
+ % second mandatory arg name of derivative
+ \edef\POL@iterindex{\the\numexpr#1\relax}%
+ \ifnum\POL@iterindex<\z@
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ {\PolDiff[-\POL@iterindex]}{\POL@AntiDiff}%
+}%
+\def\POL@AntiDiff{%
+ \ifcase\POL@iterindex\space
+ \expandafter\POL@AntiDiff@no
+ \or\expandafter\POL@AntiDiff@one
+ \else\xint_afterfi{\POL@Iterate\POL@AntiDiff@one}%
+ \fi
+}%
+\let\POL@AntiDiff@no\POL@Diff@no
+\def\POL@AntiDiff@one #1#2{\POL@AntiDiff@@one{#1}{#2}\POL@newpol{#2}}%
+\def\POL@AntiDiff@@one#1#2{%
+ \expandafter\expandafter\expandafter\POL@split
+ \csname POLuserpol@#1\endcsname;\POL@var@deg\POL@var@coeffs
+ \ifnum\POL@var@deg<\z@
+ \@namedef{POLuserpol@#2}{-1.\empty{0/1[0]}}%
+ \else
+ \edef\POL@var@coeffs{\expandafter\POL@antidiff\POL@var@coeffs\relax}%
+ \expandafter\edef\csname POLuserpol@#2\endcsname
+ {\the\numexpr\POL@var@deg+\@ne.\noexpand\empty{0/1[0]}\POL@var@coeffs}%
+ \fi
+}%
+
+%% IContent and \PolMakePrimitive (0.5)
+\def\POL@aux@mgcd@loop#1#2{%
+ \if\relax#2\expandafter\POL@aux@mgcd@exit\fi
+ \expandafter
+ \POL@aux@mgcd@loop\romannumeral0\POL@aux@gcd#1.#2.%
+}%
+\def\POL@aux@mgcd@exit
+ \expandafter
+ \POL@aux@mgcd@loop\romannumeral0\POL@aux@gcd#1.\relax.{\xintiiabs{#1}}%
+\def\POL@aux@gcd#1.#2.{%
+ \if0\xintiiSgn{#1}\expandafter\POL@aux@gcd@exit\fi
+ \expandafter\POL@aux@gcd\romannumeral0\xintmod {#2}{#1}.#1.}%
+\def\POL@aux@gcd@exit
+ \expandafter\POL@aux@gcd\romannumeral0\xintmod #1#2.#3.{{#1}}%
+
+\def\POL@icontent #1{\romannumeral0\expandafter
+ \POL@aux@mgcd@loop\romannumeral`^^@#1\relax}%
+
+\newcommand\PolIContent[1]{\romannumeral0\expandafter
+ \POL@aux@mgcd@loop\romannumeral`^^@\PolToList{#1}\relax}%
+
+
+\def\POL@makeprim@macro#1%
+ {\xintREZ{\xintNum{\xintDiv{#1}{\POL@makeprim@icontent}}}}%
+\newcommand\PolMakePrimitive[1]{%
+ % This does not need a full user declared polynomial on input, only
+ % a \POLuserpol@name macro, but on output it is fully declared
+ \edef\POL@makeprim@icontent{\PolIContent{#1}}%
+ \PolMapCoeffs\POL@makeprim@macro{#1}%
+}%
+\def\POL@makeprimitive#1{%
+ % Avoids declaring the polynomial, internal usage in \PolToSturm
+ \edef\POL@makeprim@icontent{\PolIContent{#1}}%
+ \POL@mapcoeffs\POL@makeprim@macro{#1}%
+}%
+
+
+%% Sturm Algorithm (polexpr 0.4)
+%% 0.5 uses primitive polynomials for faster evaluations afterwards
+%% 0.6 corrects misuse of \@ifstar! (mumble). \PolToSturm* was broken.
+%% 0.6's \PolToSturm* defines both normalized and unnormalized, the
+%% unnormalized using two underscores, so both are available
+%% Sole difference is that \PolToSturm* also declares them as
+%% user polynomials, whereas the non-starred only keeps the macros
+%% holding the coefficients in memory
+%% 0.6 fixes the case of a constant polynomial P which caused division
+%% by zero error from P'.
+\newcommand\PolToSturm{\@ifstar{\PolToSturm@@}{\PolToSturm@}}%
+\def\POL@aux@toint#1{\xintREZ{\xintNum{#1}}}% for polynomials with int. coeffs!
+%% Attention that some macros rely upon this one setting \POL@sturmname
+%% and \POL@sturm@N as it does
+\def\PolToSturm@#1#2{%
+ \edef\POL@sturmname{#2}%
+ % 0.6 uses 2 underscores (one before index, one after) to keep in memory
+ % the unnormalized chain
+ % This supposes #1 to be a genuine polynomial, not only a name with
+ % a \POLuserpol@#1 macro
+ \POL@let{\POL@sturmname _0_}{#1}%
+ \ifnum\PolDegree{#1}=\z@
+ \def\POL@sturm@N{0}%
+ \POL@count\z@
+ % if I applied the same as for positive degree, I should make it -1
+ % if constant is negative. I also don't worry if polynomial is zero.
+ \@namedef{POLuserpol@\POL@sturmname _0}{0.\empty{1/1[0]}}%
+ \else
+ \ifPOL@tosturm@makefirstprimitive\POL@makeprimitive{\POL@sturmname _0_}\fi
+ \POL@tosturm@dosturm
+ \fi
+ \expandafter
+ \let\csname PolSturmChainLength_\POL@sturmname\endcsname\POL@sturm@N
+ % declare the normalized ones as full-fledged polynomials
+ % \POL@count\z@
+ \xintloop
+ \POL@newpol{\POL@sturmname _\the\POL@count}%
+ \unless\ifnum\POL@sturm@N=\POL@count
+ \advance\POL@count\@ne
+ \repeat
+}%
+\def\PolToSturm@@#1#2{\PolToSturm@{#1}{#2}\POL@tosturm@declareunnormalized}%
+\def\POL@tosturm@declareunnormalized{%
+ % optionally declare also the unnormalized ones
+ \POL@count\z@
+ \xintloop
+ \POL@newpol{\POL@sturmname _\the\POL@count _}%
+ \unless\ifnum\POL@sturm@N=\POL@count
+ \advance\POL@count\@ne
+ \repeat
+}%
+\def\POL@tosturm@dosturm{%
+ \POL@Diff@@one{\POL@sturmname _0_}{\POL@sturmname _1_}%
+ % re-utiliser \POL@varcoeffs directement?
+ \POL@makeprimitive{\POL@sturmname _1_}% does not do \POL@newpol
+ \POL@count\@ne
+ \xintloop
+ \POL@divide{\POL@sturmname _\the\numexpr\POL@count-\@ne\relax _}%
+ {\POL@sturmname _\the\POL@count _}%
+ \expandafter\POL@split\POL@R;\POL@degR\POL@polR
+ \unless\ifnum\POL@degR=\m@ne
+ \advance\POL@count\@ne
+ \expandafter\let
+ \csname POLuserpol@\POL@sturmname _\the\POL@count _\endcsname\POL@R
+ \edef\POL@makeprim@icontent{-\POL@icontent\POL@polR}%
+ % this avoids the \POL@newpol from \PolMapCoeffs
+ \POL@mapcoeffs\POL@makeprim@macro{\POL@sturmname _\the\POL@count _}%
+ \repeat
+ \edef\POL@sturm@N{\the\POL@count}%
+ % normalize (now always done even by starred variant)
+ \ifnum\PolDegree{\POL@sturmname _\POL@sturm@N _}>\z@
+ % \POL@count\POL@sturm@N\relax
+ \xintloop
+ \advance\POL@count\m@ne
+ \POL@divide{\POL@sturmname _\the\POL@count _}%
+ {\POL@sturmname _\POL@sturm@N _}%
+ \expandafter
+ \let\csname POLuserpol@\POL@sturmname _\the\POL@count\endcsname\POL@Q
+ % quotient actually belongs to Z[X] and is primitive
+ \POL@mapcoeffs\POL@aux@toint{\POL@sturmname _\the\POL@count}%
+ \ifnum\POL@count>\z@
+ \repeat
+ \@namedef{POLuserpol@\POL@sturmname _\POL@sturm@N}{0.\empty{1/1[0]}}%
+ \else % they are already normalized
+ \advance\POL@count\@ne % attention to include last one also
+ \xintloop
+ \advance\POL@count\m@ne
+ \expandafter\let
+ \csname POLuserpol@\POL@sturmname _\the\POL@count\expandafter\endcsname
+ \csname POLuserpol@\POL@sturmname _\the\POL@count _\endcsname
+ \ifnum\POL@count>\z@
+ \repeat
+ \fi
+ % Back to \PolToSturm@, \POL@count holds 0
+}%
+\newcommand\PolSturmChainLength[1]
+ {\romannumeral`^^@\csname PolSturmChainLength_#1\endcsname}%
+
+\newcommand\PolSetToSturmChainSignChangesAt[4][\global]{%
+ \edef\POL@sturmchain@X{\xintREZ{#4}}%
+ \edef\POL@sturmname{#3}%
+ \edef\POL@sturmlength{\PolSturmChainLength{\POL@sturmname}}%
+ \POL@sturmchain@getSV@at\POL@sturmchain@X
+ #1\let#2\POL@sturmchain@SV
+}%
+\def\POL@sturmchain@getSV@at#1{% ATTENTION USES \POL@count
+ \def\POL@sturmchain@SV{0}%
+ \edef\POL@sturmchain@sign{\xintiiSgn{\POL@eval{\POL@sturmname _0}{#1}}}%
+ \let\POL@isolz@lastsign\POL@sturmchain@sign
+ \POL@count \z@
+ \ifnum\POL@isolz@lastsign=\z@
+ \edef\POL@isolz@lastsign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _1}{#1}}}%
+ \POL@count \@ne
+ \fi
+ \xintloop
+ \unless\ifnum\POL@sturmlength=\POL@count
+ \advance\POL@count \@ne
+ \edef\POL@isolz@newsign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _\the\POL@count}{#1}}}%
+ \ifnum\POL@isolz@newsign=\numexpr-\POL@isolz@lastsign\relax
+ \edef\POL@sturmchain@SV{\the\numexpr\POL@sturmchain@SV+\@ne}%
+ \let\POL@isolz@lastsign=\POL@isolz@newsign
+ \fi
+ \repeat
+}%
+\newcommand\PolSetToNbOfZerosWithin[5][\global]{%
+ \edef\POL@tmpA{\xintREZ{#4}}%
+ \edef\POL@tmpB{\xintREZ{#5}}%
+ \edef\POL@sturmname{#3}%
+ \edef\POL@sturmlength{\PolSturmChainLength{\POL@sturmname}}%
+ \POL@sturmchain@getSV@at\POL@tmpA
+ \let\POL@SVA\POL@sturmchain@SV
+ \POL@sturmchain@getSV@at\POL@tmpB
+ \let\POL@SVB\POL@sturmchain@SV
+ \ifnum\POL@SVA<\POL@SVB\space
+ #1\edef#2{\the\numexpr\POL@SVB-\POL@SVA}%
+ \else
+ #1\edef#2{\the\numexpr\POL@SVA-\POL@SVB}%
+ \fi
+}%
+
+
+% 0.6 added starred variant to count multiplicities
+% 0.7 added double starred variant to locate all rational roots
+\newcommand\PolSturmIsolateZeros{\@ifstar
+ {\PolSturmIsolateZerosAndGetMultiplicities}%
+ {\PolSturmIsolateZeros@}%
+}%
+\newcommand\PolSturmIsolateZerosAndGetMultiplicities{\@ifstar
+ {\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots}%
+ {\PolSturmIsolateZerosAndGetMultiplicities@}%
+}%
+% on aurait besoin de ça dans xint, mais il aurait un \xintRaw{#1} alors
+\def\POL@xintfrac@getNDE #1%
+ {\expandafter\POL@xintfrac@getNDE@i\romannumeral`^^@#1}%
+\def\POL@xintfrac@getNDE@i #1/#2[#3]#4#5#6{\def#4{#1}\def#5{#2}\def#6{#3}}%
+\newcommand\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots[2][\empty]{%
+ \PolSturmIsolateZerosAndFindRationalRoots[#1]{#2}%
+ \ifnum\POL@isolz@NbOfRoots>\z@
+ % get multiplicities of irrational (real) roots, if any
+ \ifnum\POL@findrat@nbofirrroots>\z@
+ \POL@findrat@getirrmult
+ \fi
+ \POL@isolzmult@defvar@M
+ \fi
+}%
+% added at 0.7
+\newcommand\PolSturmIsolateZerosAndFindRationalRoots[2][\empty]{%
+ % #1 optional E such that roots are searched in -10^E < x < 10^E
+ % both -10^E and +10^E must not be roots!
+ % #2 name of Sturm chain (already pre-computed)
+ \edef\POL@sturmname{#2}%
+ \edef\POL@sturm@N{\@nameuse{PolSturmChainLength_\POL@sturmname}}%
+ % isolate the roots (detects case of constant polynomial)
+ \PolSturmIsolateZeros@{\POL@sturmname}%
+ \ifnum\POL@isolz@NbOfRoots=\z@
+ % no real roots, define empty arrays nevertheless
+ \begingroup\globaldefs\@ne
+ \expandafter\xintAssignArray\expandafter\to\csname POL_ZM\POL@sturmname*\endcsname
+ \expandafter\xintAssignArray\expandafter\to\csname POL_RI\POL@sturmname*\endcsname
+ \endgroup
+ \else
+ % all we currently know is that multiplicities are at least one
+ \begingroup\globaldefs\@ne
+ \expandafter\POL@initarray\csname POL_ZM\POL@sturmname*\endcsname{1}%
+ \endgroup
+ % on ne va pas utiliser de Horner, mais des divisions par X - x, et ces
+ % choses vont évoluer, ainsi que le coefficient dominant entier
+ % (pour \POL@divide entre autres if faut des noms de user pol)
+ \expandafter\let
+ \csname POLuserpol@\POL@sturmname\POL@sqfnorr\expandafter\endcsname
+ \csname POLuserpol@\POL@sturmname _0\endcsname
+ \expandafter\let
+ \csname POLuserpol@\POL@sturmname\POL@norr\expandafter\endcsname
+ \csname POLuserpol@\POL@sturmname _0_\endcsname
+ % attention formé avec\xintREZ d'où le \xintAbs pas \xintiiAbs
+ % D and its exponent E will get updated along the way
+ \edef\POL@findrat@D{\xintAbs{\PolLeadingCoeff{\POL@sturmname _0}}}%
+ \POL@xintfrac@getNDE\POL@findrat@D\POL@findrat@Dint\POL@_\POL@findrat@Dexp
+ \xintiiifOne{\POL@findrat@Dint}
+ {\let\POL@findrat@E\POL@findrat@Dexp} % aussi ok pour 1[0]
+ {\edef\POL@findrat@E{\the\numexpr\xintLen{\POL@findrat@Dint}%
+ +\POL@findrat@Dexp}}%
+% ATTENTION QUE LA CONVENTION DE SIGNE POUR \POL@findrat@E EST OPPOSÉE À CELLE
+% POUR LE CODE PLUS ANCIEN FAISANT "REFINE"
+ \POL@initarray\POL@IfMultIsKnown\xint_secondoftwo
+ \let\POL@findrat@nbofirrroots\POL@isolz@NbOfRoots
+ % find all rational roots, and their multiplicities,
+ % factor them out in passing from original (Sturm root) polynomial
+ \ifnum\POL@findrat@E<7
+ \def\POL@findrat@index{1}%
+ \POL@findrat@loop@secondpass@direct
+ \else
+ % we do a first pass scanning for "small" roots p/q (i.e. q < 1000)
+ \def\POL@findrat@index{1}%
+ \POL@findrat@loop@firstpass
+ % and now we do the final pass finding them all
+ \def\POL@findrat@index{1}%
+ \POL@findrat@loop@secondpass
+ \fi
+ % declare the new polynomials
+ \POL@newpol{\POL@sturmname\POL@sqfnorr}% without multiplicities
+ \POL@newpol{\POL@sturmname\POL@norr}% with multiplicities
+ % declare the array holding the interval indices for the rational roots
+ \expandafter\POL@findrat@doRRarray\csname POL_RI\POL@sturmname*\endcsname
+ \fi
+}%
+\def\POL@findrat@doRRarray#1{%
+ % il faudrait un \xintAssignArray* qui fasse même expansion que \xintFor*
+ \edef\POL@temp{%
+ \xintiloop[1+1]
+ \romannumeral0\csname POL_ZK\POL@sturmname*\xintiloopindex\endcsname
+ \xintbracediloopindex % I should have named it \xintiloopbracedindex...
+ {}%
+ \ifnum\xintiloopindex<\POL@isolz@NbOfRoots\space
+ \repeat }%
+ \begingroup\globaldefs\@ne
+ % attention de ne surtout pas faire un \expandafter ici, car en cas d'un
+ % seul item, \xintAssignArray l'unbraces...
+ \xintAssignArray\POL@temp\to#1%
+ \endgroup
+}%
+\def\POL@findrat@loop@firstpass{%
+ \PolSturmIfZeroExactlyKnown{\POL@sturmname}{\POL@findrat@index}%
+ \POL@findrat@loop@decimal% get its multiplicity
+ \POL@findrat@loop@aa % refine interval and check
+ \edef\POL@findrat@index{\the\numexpr\POL@findrat@index+\@ne}%
+ \ifnum\POL@findrat@index>\POL@isolz@NbOfRoots
+ \else
+ \expandafter\POL@findrat@loop@firstpass
+ \fi
+}%
+\def\POL@findrat@loop@aa{%
+ % we do a first pass to identify roots with denominators < 1000
+ \PolEnsureIntervalLength{\POL@sturmname}{\POL@findrat@index}{-6}%
+ % attention that perhaps now the root is known!
+ \PolSturmIfZeroExactlyKnown{\POL@sturmname}{\POL@findrat@index}%
+ \POL@findrat@loop@decimal
+ \POL@findrat@loop@a
+}%
+\def\POL@findrat@loop@decimal{% we have an already found decimal root
+ % we do not go via @storeit, as it is already stored
+ % j'ai beaucoup hésité néanmoins, car je pourrais faire \xintIrr ici,
+ % mais attention aussi à l'interaction avec le \PolDecToString. Les racines
+ % trouvées directement (qui peuvent être des nombres décimaux) sont elles
+ % stockées comme fraction irréductibles (modulo action additionnelle de
+ % \PolDecToString).
+ \POL@xintfrac@getNDE
+ {\xintIrr{\POL@xintexprGetVar{\POL@sturmname L_\POL@findrat@index}}[0]}%
+ \POL@findrat@xN\POL@findrat@xD\POl@_
+ % we can't move this to updatequotients because other branch will
+ % need to do the division first anyhow
+ \edef\POLuserpol@_findrat@oneterm{1.\noexpand\empty
+ {\xintiiOpp\POL@findrat@xN/1[0]}{\POL@findrat@xD/1[0]}}%
+ \POL@divide{\POL@sturmname\POL@sqfnorr}{_findrat@oneterm}% the one without mult.
+ %\expandafter\POL@split\POL@R;\POL@degR\POL@polR
+ \POL@findrat@loop@updatequotients
+ \POL@findrat@loop@getmultiplicity
+}%
+% lacking from xint 1.3c, but \xintSgn has overhead, so we define ii version
+\def\xintiiifNeg{\romannumeral0\xintiiifneg }%
+\def\xintiiifneg #1%
+{%
+ \ifcase \xintiiSgn{#1}
+ \expandafter\xint_stop_atsecondoftwo
+ \or\expandafter\xint_stop_atsecondoftwo
+ \else\expandafter\xint_stop_atfirstoftwo
+ \fi
+}%
+\def\POL@findrat@getE #1/1[#2]{#2}% /1 as it should be there.
+% so an error will arise if not but cf \POL@refine@getE where I did not put it
+\def\POL@findrat@loop@a{%
+ % attention that the width may have been already smaller than 10^{-6}
+ \POL@get@IsoLeft@rawin
+ \POL@get@IsoRight@rawin
+ \edef\POL@findrat@localW
+ {\the\numexpr-\expandafter\POL@findrat@getE
+ % do I really need the \xintREZ?
+ \romannumeral0\xintrez
+ {\xintSub{\POL@IsoRight@rawin}{\POL@IsoLeft@rawin}}%
+ }% at least 6, maybe larger
+ \expandafter\POL@get@Int@aux
+ \POL@IsoLeft@rawin\POL@IsoLeft@Int{-\POL@findrat@localW}%
+ \expandafter\POL@get@Int@aux
+ \POL@IsoRight@rawin\POL@IsoRight@Int{-\POL@findrat@localW}%
+ % in case of odd, some waste here
+ \edef\POL@findrat@halflocalW{\the\numexpr(\POL@findrat@localW+1)/2-1}%
+ % Legendre Theorem will be used now but we separate a branch where
+ % everything can be done with \numexpr
+ \ifnum\POL@findrat@localW>9
+ % not implemented yet by lazyness!
+ % this root will be handled in second pass only
+ \else
+ \POL@findrat@gcdloop
+ \fi
+}%
+\def\POL@findrat@gcdloop{%
+ % we must be careful with sign
+ % but we are certain no extremity is a root
+ \let\POL@findrat@ifnegative\xint_secondoftwo
+ \xintiiifSgn\POL@IsoLeft@Int
+ \POL@findrat@gcdloop@n
+ \POL@error@thisisimpossible
+ \POL@findrat@gcdloop@p
+}%
+\def\POL@findrat@gcdloop@n{%
+ \let\POL@findrat@ifnegative\xint_firstoftwo
+ \let\POL@temp\POL@IsoRight@Int
+ \edef\POL@IsoRight@Int{\xintiiOpp{\POL@IsoLeft@Int}}%
+ \edef\POL@IsoLeft@Int{\xintiiOpp{\POL@temp}}%
+ \POL@findrat@gcdloop@p
+}%
+\def\POL@findrat@gcdloop@p{%
+ \edef\POL@findrat@gcdloop@Ap{\xintDec{\xintDouble\POL@IsoRight@Int}}%
+ \edef\POL@findrat@gcdloop@A
+ % at most 2e9: this is acceptable to \numexpr
+ {2\romannumeral\xintreplicate\POL@findrat@localW{0}}%
+ \xintAssign
+ \xintiiDivision\POL@findrat@gcdloop@Ap\POL@findrat@gcdloop@A
+ \to\POL@findrat@gcdloop@B\POL@findrat@gcdloop@An
+ % on fait de la tambouille pour n'utiliser que \numexpr par la suite
+ % le reste @An est < 2.10^9 au pire donc ok pour \numexpr
+ % we will drop integral part in our updating P
+ \let\POL@findrat@gcdloop@Binitial\POL@findrat@gcdloop@B
+ \def\POL@findrat@gcdloop@B{0}% do as if B1 = 0
+ \def\POL@findrat@gcdloop@Pp{1}% P0
+ \def\POL@findrat@gcdloop@P{0}% P1
+ \def\POL@findrat@gcdloop@Qp{0}% Q0
+ \def\POL@findrat@gcdloop@Q{1}% Q1
+ % A2=An can not be zero, as Ap (=A0) is odd and A (=A1=200...000) is even
+ % first Binitial + P1/Q1 ( = Binitial) can not be root
+ \let\POL@findrat@gcdloop@Ap\POL@findrat@gcdloop@A % A1
+ \let\POL@findrat@gcdloop@A\POL@findrat@gcdloop@An % A2
+ \def\next{\POL@findrat@gcdloop@update}%
+ \def\POL@findrat@gcdloop@done{0}%
+ \POL@findrat@gcdloop@body
+}%
+\def\POL@findrat@gcdloop@body{%
+ % annoying that \numexpr has no divmod... use counts? but groups annoying
+ \edef\POL@findrat@gcdloop@B
+ {\the\numexpr(\POL@findrat@gcdloop@Ap+\POL@findrat@gcdloop@A/2)/%
+ \POL@findrat@gcdloop@A - \@ne}%
+ \edef\POL@findrat@gcdloop@An
+ {\the\numexpr\POL@findrat@gcdloop@Ap-%
+ \POL@findrat@gcdloop@B*\POL@findrat@gcdloop@A}%
+ \edef\POL@findrat@gcdloop@Pn
+ {\the\numexpr\POL@findrat@gcdloop@Pp+%
+ \POL@findrat@gcdloop@B*\POL@findrat@gcdloop@P}%
+ \edef\POL@findrat@gcdloop@Qn
+ {\the\numexpr\POL@findrat@gcdloop@Qp+%
+ \POL@findrat@gcdloop@B*\POL@findrat@gcdloop@Q}%
+ \ifnum\expandafter\xintLength\expandafter{\POL@findrat@gcdloop@Qn}%
+ >\POL@findrat@halflocalW\space
+ \let\next\empty % no solution was found
+ \else
+ % with these conditions on denom, only candidates are by Legendre
+ % theorem among the convergents as computed here
+ \ifnum\POL@findrat@gcdloop@Qn>\POL@findrat@gcdloop@An\space
+ % means that P/Q is in interval and is thus a candidate
+ % it is automatically irreducible
+ \edef\POL@findrat@x{\xintiiAdd
+ {\xintiiMul{\POL@findrat@gcdloop@Qn}{\POL@findrat@gcdloop@Binitial}}%
+ {\POL@findrat@gcdloop@Pn}/\POL@findrat@gcdloop@Qn[0]}%
+ \POL@findrat@gcdloop@testit
+ \if1\POL@findrat@gcdloop@done
+ \let\next\empty % a solution was found
+ \fi
+ \fi
+ \fi
+ \next
+}%
+\def\POL@findrat@gcdloop@update{%
+ \ifnum\POL@findrat@gcdloop@An>\z@
+ \let\POL@findrat@gcdloop@Ap\POL@findrat@gcdloop@A
+ \let\POL@findrat@gcdloop@A\POL@findrat@gcdloop@An
+ \let\POL@findrat@gcdloop@Pp\POL@findrat@gcdloop@P
+ \let\POL@findrat@gcdloop@P\POL@findrat@gcdloop@Pn
+ \let\POL@findrat@gcdloop@Qp\POL@findrat@gcdloop@Q
+ \let\POL@findrat@gcdloop@Q\POL@findrat@gcdloop@Qn
+ \expandafter\POL@findrat@gcdloop@body
+ \fi
+}%
+\def\POL@findrat@gcdloop@testit{%
+ % zero should never occur here
+ \POL@findrat@ifnegative{\edef\POL@findrat@x{-\POL@findrat@x}}{}%
+ \POL@xintfrac@getNDE\POL@findrat@x\POL@findrat@xN\POL@findrat@xD\POL@_
+ \edef\POLuserpol@_findrat@oneterm{1.\noexpand\empty
+ {\xintiiOpp{\POL@findrat@xN}/1[0]}{\POL@findrat@xD/1[0]}}%
+ \POL@divide{\POL@sturmname\POL@sqfnorr}{_findrat@oneterm}% the one without mult.
+ \expandafter\POL@split\POL@R;\POL@degR\POL@polR
+ \ifnum\POL@degR=\m@ne % found a root
+ \POL@findrat@loop@storeit
+ \POL@findrat@loop@updatequotients
+ \POL@findrat@loop@getmultiplicity % will continue updating the mult. one
+ \def\POL@findrat@gcdloop@done{1}%
+ \fi
+}%
+% This is second phase
+\def\POL@findrat@loop@secondpass{%
+ \PolSturmIfZeroExactlyKnown{\POL@sturmname}{\POL@findrat@index}%
+ {}% nothing more to be done, already stored
+ \POL@findrat@loop@bb % refine interval and check
+ \edef\POL@findrat@index{\the\numexpr\POL@findrat@index+\@ne}%
+ \ifnum\POL@findrat@index>\POL@isolz@NbOfRoots
+ \else
+ \expandafter\POL@findrat@loop@secondpass
+ \fi
+}%
+\def\POL@findrat@loop@secondpass@direct{%
+ \PolSturmIfZeroExactlyKnown{\POL@sturmname}{\POL@findrat@index}%
+ \POL@findrat@loop@decimal
+ \POL@findrat@loop@bb
+ \edef\POL@findrat@index{\the\numexpr\POL@findrat@index+\@ne}%
+ \ifnum\POL@findrat@index>\POL@isolz@NbOfRoots
+ \else
+ \expandafter\POL@findrat@loop@secondpass@direct
+ \fi
+}%
+\def\POL@findrat@loop@bb{%
+ \PolEnsureIntervalLength{\POL@sturmname}{\POL@findrat@index}{-\POL@findrat@E}%
+ % ATTENTION THAT PERHAPS NOW THE ROOT IS KNOWN!
+ \PolSturmIfZeroExactlyKnown{\POL@sturmname}{\POL@findrat@index}%
+ \POL@findrat@loop@decimal
+ \POL@findrat@loop@b
+}%
+\def\POL@findrat@loop@b{%
+ \edef\POL@findrat@Lscaled{\xintMul{\POL@findrat@D}%
+ {\POL@xintexprGetVar{\POL@sturmname L_\POL@findrat@index}}}%
+ \edef\POL@findrat@Rscaled{\xintMul{\POL@findrat@D}%
+ {\POL@xintexprGetVar{\POL@sturmname R_\POL@findrat@index}}}%
+ \xintiiifNeg{\POL@findrat@Lscaled}% using ii version is an abuse
+ {% negative interval (right bound possibly zero!)
+ % truncate towards zero (i.e. to the right) the left bound
+ \edef\POL@findrat@Num{\xintNum{\POL@findrat@Lscaled}/1[0]}%
+ % interval boundaries are not root hence in case that was exact
+ % this will not be found as a root; check if in interval
+ \xintifLt\POL@findrat@Num\POL@findrat@Rscaled
+ \POL@findrat@loop@c
+ {}% iterate
+ }%
+ {% positive interval (left bound possibly zero!)
+ % truncate towards zero (i.e. to the left) the right bound
+ \edef\POL@findrat@Num{\xintNum{\POL@findrat@Rscaled}/1[0]}%
+ % check if in interval
+ \xintifGt\POL@findrat@Num\POL@findrat@Lscaled
+ \POL@findrat@loop@c
+ {}% iterate
+ }%
+}%
+\def\POL@findrat@loop@c{%
+ % safer to do the edef as \POL@findrat@x used later in storeit
+ \edef\POL@findrat@x{\xintIrr{\xintDiv\POL@findrat@Num\POL@findrat@D}[0]}%
+ \POL@xintfrac@getNDE\POL@findrat@x\POL@findrat@xN\POL@findrat@xD\POL@_
+ \edef\POLuserpol@_findrat@oneterm{1.\noexpand\empty
+ {\xintiiOpp{\POL@findrat@xN}/1[0]}{\POL@findrat@xD/1[0]}}%
+ \POL@divide{\POL@sturmname\POL@sqfnorr}{_findrat@oneterm}% the one without mult.
+ \expandafter\POL@split\POL@R;\POL@degR\POL@polR
+ \ifnum\POL@degR=\m@ne % found a root
+ \POL@findrat@loop@storeit
+ \POL@findrat@loop@updatequotients
+ \POL@findrat@loop@getmultiplicity % will continue updating the mult. one
+ \fi
+ % iterate
+}%
+\def\POL@findrat@loop@storeit{%
+ % update storage, I can not use storeleftandright here (due to rawout etc...)
+ \expandafter
+ \xdef\csname POL_ZL\POL@sturmname*\POL@findrat@index\endcsname
+ {\PolDecToString{\POL@findrat@x}}%
+ \global\expandafter
+ \let\csname POL_ZR\POL@sturmname*\POL@findrat@index\expandafter\endcsname
+ \csname POL_ZL\POL@sturmname*\POL@findrat@index\endcsname
+ \global\expandafter
+ \let\csname POL_ZK\POL@sturmname*\POL@findrat@index\endcsname
+ \xint_stop_atfirstoftwo
+ \begingroup\xintglobaldefstrue
+ % skip some overhead of \xintdefvar...
+ \XINT_expr_defvar_one{\POL@sturmname L_\POL@findrat@index}%
+ {\csname .=\POL@findrat@x\endcsname}%
+ \XINT_expr_defvar_one{\POL@sturmname R_\POL@findrat@index}%
+ {\csname .=\POL@findrat@x\endcsname}%
+ \XINT_expr_defvar_one{\POL@sturmname Z_\POL@findrat@index _isknown}%
+ {\csname .=1\endcsname}%
+ \endgroup
+}%
+\def\POL@findrat@loop@updatequotients{%
+ % attention last division must have been one testing vanishing of\POL@sqfnorr
+ \expandafter\let\csname POLuserpol@\POL@sturmname\POL@sqfnorr\endcsname\POL@Q
+ % quotient belongs to Z[X] and is primitive
+ \POL@mapcoeffs\POL@aux@toint{\POL@sturmname\POL@sqfnorr}%
+ % update the one with multiplicities
+ \POL@divide{\POL@sturmname\POL@norr}{_findrat@oneterm}%
+ \expandafter\let\csname POLuserpol@\POL@sturmname\POL@norr\endcsname\POL@Q
+ \POL@mapcoeffs\POL@aux@toint{\POL@sturmname\POL@norr}
+ % updating of \POL@findrat@D at end of execution of getmultiplicity
+}%
+\def\POL@findrat@loop@getmultiplicity{%
+ % the one without multiplicity must not be divided again!
+ % check if we have remaining multiplicity
+ \POL@divide{\POL@sturmname\POL@norr}{_findrat@oneterm}%
+ \expandafter\POL@split\POL@R;\POL@degR\POL@polR
+ \ifnum\POL@degR=\m@ne % yes
+ \expandafter\let\csname POLuserpol@\POL@sturmname\POL@norr\endcsname\POL@Q
+ \POL@mapcoeffs\POL@aux@toint{\POL@sturmname\POL@norr}%
+ \expandafter
+ \xdef
+ \csname POL_ZM\POL@sturmname*\POL@findrat@index\endcsname
+ {\the\numexpr
+ \csname POL_ZM\POL@sturmname*\POL@findrat@index\endcsname+\@ne}%
+ \expandafter\POL@findrat@loop@getmultiplicity
+ \else
+ % done with multiplicity for this rational root, update stuff
+ \edef\POL@findrat@nbofirrroots
+ {\the\numexpr\POL@findrat@nbofirrroots-\@ne}%
+ \@namedef{POL@IfMultIsKnown\POL@findrat@index}{\xint_firstoftwo}%
+ \edef\POL@findrat@D{\xintAbs{\PolLeadingCoeff{\POL@sturmname\POL@sqfnorr}}}%
+ \POL@xintfrac@getNDE\POL@findrat@D\POL@findrat@Dint\POL@_\POL@findrat@Dexp
+ \xintiiifOne{\POL@findrat@Dint}
+ {\let\POL@findrat@E\POL@findrat@Dexp} % aussi ok pour 1[0]
+ {\edef\POL@findrat@E{\the\numexpr\xintLen{\POL@findrat@Dint}%
+ +\POL@findrat@Dexp}}%
+ \fi
+}%
+\def\POL@findrat@getirrmult{%
+ % first get the GCD of remaining pol with its derivative
+ \POL@divide{\POL@sturmname\POL@norr}{\POL@sturmname\POL@sqfnorr}%
+ \expandafter\let
+ % attention au _ (cf. grosse astuce pour \POL@isolzmult@loop)
+ \csname POLuserpol@@_1\POL@sturmname _\endcsname\POL@Q
+ \ifnum\PolDegree{@_1\POL@sturmname _}>\z@
+ % il reste des multiplicités (mais peut-être pour des racines complexes)
+ % (ou pour des racines en-dehors de l'intervalle optionnel)
+ % attention recyclage ici de \POL@isolzmult@loop qui dépend de
+ % la grosse astuce avec \@gobble
+ \POL@makeprimitive{@_1\POL@sturmname _}%
+ \let\POL@originalsturmname\POL@sturmname
+ % trick to get isolzmult@loop to define @@lastGCD to @_1sturmname_
+ % because it will do \POL@sturmname _\POL@sturm@N _
+ \edef\POL@sturmname{@_1\POL@sturmname}%
+ \let\POL@sturm@N\@gobble% !
+ \let\POL@isolz@NbOfRoots@with_unknown_mult\POL@findrat@nbofirrroots
+ \POL@tosturm@makefirstprimitivefalse
+ \POL@isolzmult@loop
+ \POL@tosturm@makefirstprimitivetrue
+ \let\POL@sturmname\POL@originalsturmname
+ \fi
+}%
+
+
+\newcommand\PolSturmIsolateZerosAndGetMultiplicities@[2][\empty]{%
+ % #1 optional E such that roots are searched in -10^E < x < 10^E
+ % both -10^E and +10^E must not be roots!
+ % #2 name of Sturm chain (already pre-computed)
+ \edef\POL@sturmname{#2}%
+ \edef\POL@sturm@N{\@nameuse{PolSturmChainLength_\POL@sturmname}}%
+ % isolate the roots (detects case of constant polynomial)
+ \PolSturmIsolateZeros@{\POL@sturmname}%
+ \ifnum\POL@isolz@NbOfRoots=\z@
+ % no roots, define empty array nevertheless
+ \begingroup\globaldefs\@ne
+ \expandafter\xintAssignArray\expandafter\to\csname POL_ZM\POL@sturmname*\endcsname
+ \endgroup
+ \else
+ % all we currently know is that multiplicities are at least one
+ \begingroup\globaldefs\@ne
+ \expandafter\POL@initarray\csname POL_ZM\POL@sturmname*\endcsname{1}%
+ \endgroup
+ % check if GCD had positive degree (hence some roots, maybe complex, have
+ % multiplicity)
+ \ifnum\PolDegree{\POL@sturmname _\POL@sturm@N _}>\z@
+ % scratch array of flags to signal known multiplicities
+ \POL@initarray\POL@IfMultIsKnown\xint_secondoftwo
+ % this count has utility for the case there are other roots
+ % either complex or outside interval (in case of optional argument)
+ \let\POL@isolz@NbOfRoots@with_unknown_mult\POL@isolz@NbOfRoots
+ % store Sturm chain name, it is needed and altered in isolzmult@loop
+ \let\POL@originalsturmname\POL@sturmname
+ \POL@tosturm@makefirstprimitivefalse
+ \POL@isolzmult@loop
+ \POL@tosturm@makefirstprimitivetrue
+ \let\POL@sturmname\POL@originalsturmname
+ \fi
+ \POL@isolzmult@defvar@M
+ \fi
+}%
+\def\POL@isolzmult@defvar@M{%
+ % Attention that is used not only in ...GetMultiplicities@ but also
+ % in FindRationalRoots
+ \begingroup\xintglobaldefstrue
+ % added at 0.7
+ \let\x\POL@isolz@NbOfRoots
+ \xintloop
+ % skip some overhead of \xintdefvar...
+ \XINT_expr_defvar_one{\POL@sturmname M_\x}%
+ {\csname .=\csname POL_ZM\POL@sturmname*\x\endcsname\endcsname}%
+ \edef\x{\the\numexpr\x-\@ne}%
+ \ifnum\x>\z@
+ \repeat
+ \endgroup
+}%
+\def\POL@isolzmult@loop{%
+ % we are here only if last iteration gave a new GCD still of degree > 0
+ % \POL@sturm@N is the one from last iteration
+ % Attention to not use \POL@sturmname directly in first arg. of \PolToSturm
+ % Attention that we need for the case of known roots also to have the last
+ % GCD (with its multiplicities) known as a genuine polynomial
+ % - because of usage of \POL@eval in @isknown branch
+ % - because \PolToSturm@ does a \POL@let which would be anomalous
+ % if the extended structure is not existing
+ \edef\POL@isolzmult@lastGCD{\POL@sturmname _\POL@sturm@N _}%
+ \edef\POL@isolzmult@newsturmname{@_1\POL@sturmname}%
+ \POL@newpol{\POL@isolzmult@lastGCD}%
+ \PolToSturm@{\POL@isolzmult@lastGCD}{\POL@isolzmult@newsturmname}%
+ % now both \POL@sturmname and \POL@sturm@N have changed
+ \edef\POL@isolzmult@newGCDdegree{\PolDegree{\POL@sturmname _\POL@sturm@N _}}%
+ \let\POL@isolzmult@index\POL@isolz@NbOfRoots
+ \xintloop
+ % ATTENTION that this executes macros which also modifies \POL@sturmname!
+ % (but not \POL@sturm@N)
+ \POL@isolzmult@doone
+ \edef\POL@isolzmult@index{\the\numexpr\POL@isolzmult@index-\@ne}%
+ \if1\ifnum\POL@isolz@NbOfRoots@with_unknown_mult=\z@ 0\fi
+ \ifnum\POL@isolzmult@index=\z@ 0\fi 1%
+ \repeat
+ \let\POL@sturmname\POL@isolzmult@newsturmname
+ \if1\ifnum\POL@isolz@NbOfRoots@with_unknown_mult=\z@ 0\fi
+ % (if new GCD is constant, time to abort)
+ \ifnum\POL@isolzmult@newGCDdegree=\z@ 0\fi 1%
+ \expandafter\POL@isolzmult@loop
+ \fi
+}%
+\def\POL@isolzmult@doone{%
+ \csname POL@IfMultIsKnown\POL@isolzmult@index\endcsname
+ {}% nothing to do
+ {\POL@SturmIfZeroExactlyKnown{\POL@originalsturmname}%
+ {\POL@isolzmult@index}%
+ \POL@isolzmult@loop@isknown
+ \POL@isolzmult@loop@isnotknown
+ \POL@isolzmult@loop@sharedbody
+ }%
+}%
+\def\POL@isolzmult@loop@isknown{%
+ \xintifZero
+ % attention that \POL@eval requires a declared polynomial
+ {\POL@eval{\POL@isolzmult@lastGCD}%
+ {\POL@xintexprGetVar{\POL@originalsturmname L_\POL@isolzmult@index}}}%
+ {\let\POL@isolzmult@haszero\@ne}%
+ {\let\POL@isolzmult@haszero\z@}%
+}%
+\def\POL@isolzmult@loop@isnotknown{%
+ \edef\POL@isolzmult@loop@A
+ {\POL@xintexprGetVar{\POL@originalsturmname L_\POL@isolzmult@index}}
+ \edef\POL@isolzmult@loop@B
+ {\POL@xintexprGetVar{\POL@originalsturmname
+ R_\POL@isolzmult@index}}
+ % attention that \PolSetToNbOfZerosWithin sets \POL@sturmname to 2nd argument
+ \PolSetToNbOfZerosWithin
+ \POL@isolzmult@haszero % nb of zeros A < x <= B, here 0 or 1
+ \POL@isolzmult@newsturmname
+ \POL@isolzmult@loop@A
+ \POL@isolzmult@loop@B
+}%
+\def\POL@isolzmult@loop@sharedbody{%
+ \ifnum\POL@isolzmult@haszero>\z@
+ \expandafter
+ \xdef
+ \csname POL_ZM\POL@originalsturmname*\POL@isolzmult@index\endcsname
+ {\the\numexpr
+ \csname POL_ZM\POL@originalsturmname
+ *\POL@isolzmult@index\endcsname+\@ne}%
+ \else
+ % multiplicity now known, no need to check this index in future
+ \@namedef{POL@IfMultIsKnown\POL@isolzmult@index}{\xint_firstoftwo}%
+ \edef\POL@isolz@NbOfRoots@with_unknown_mult
+ {\the\numexpr\POL@isolz@NbOfRoots@with_unknown_mult-\@ne}%
+ \fi
+}%
+
+
+\newcommand\PolSturmIsolateZeros@[2][\empty]{%
+ % #1 optional E such that roots are searched in -10^E < x < 10^E
+ % both -10^E and +10^E must not be roots!
+ % #2 name of Sturm chain (already pre-computed from a given polynomial)
+ % For reasons I have forgotten (no time now) this code **must** be used
+ % with a *normalized* Sturm chain.
+ \edef\POL@sturmname{#2}%
+ \edef\POL@sturmlength{\PolSturmChainLength{#2}}%
+ % attention to constant polynomial, we must redefine the arrays then
+ \ifnum\POL@sturmlength>\z@
+ \ifx\empty#1\relax
+ \POL@isolz@getsignchanges@plusinf
+ \POL@isolz@getsignchanges@minusinf
+ \else
+ \edef\POL@isolz@E{\the\numexpr\xint_zapspaces #1 \xint_gobble_i\relax}%
+ \POL@sturmchain@getSV@at{1[\POL@isolz@E]}%
+ \let\POL@isolz@plusinf@SV \POL@sturmchain@SV
+ \let\POL@isolz@plusinf@sign\POL@sturmchain@sign
+ \POL@sturmchain@getSV@at{-1[\POL@isolz@E]}%
+ \let\POL@isolz@minusinf@SV \POL@sturmchain@SV
+ \let\POL@isolz@minusinf@sign\POL@sturmchain@sign
+ \ifnum\POL@isolz@plusinf@sign=\z@
+ \PackageError{polexpr}%
+{The polynomial #2 vanishes at set upper bound 10^\POL@isolz@E}%
+{Compile again with a bigger exponent in source. (X to abort).}%
+ \fi
+ \ifnum\POL@isolz@minusinf@sign=\z@
+ \PackageError{polexpr}%
+{The polynomial #2 vanishes at set lower bound -10^\POL@isolz@E}%
+{Compile again with a bigger exponent in source. (X to abort).}%
+ \fi
+ \fi
+ \edef\POL@isolz@NbOfRoots
+ {\the\numexpr\POL@isolz@minusinf@SV-\POL@isolz@plusinf@SV}%
+ \else
+ % constant polynomial
+ \def\POL@isolz@NbOfRoots{0}%
+ \fi
+ \ifnum\POL@isolz@NbOfRoots=\z@
+ \begingroup\globaldefs\@ne
+ \expandafter\xintAssignArray\expandafter\to\csname POL_ZL#2*\endcsname
+ \expandafter\xintAssignArray\expandafter\to\csname POL_ZR#2*\endcsname
+ \expandafter\xintAssignArray\expandafter\to\csname POL_ZK#2*\endcsname
+ \endgroup
+ \else
+ \begingroup\globaldefs\@ne
+ \expandafter\POL@initarray\csname POL_ZL#2*\endcsname{0}%
+ \expandafter\POL@initarray\csname POL_ZR#2*\endcsname{0}%
+ \expandafter\POL@initarray\csname POL_ZK#2*\endcsname
+ \xint_stop_atsecondoftwo
+ \endgroup
+ \ifx\empty#1\relax\expandafter\POL@isolz@getaprioribound\fi
+ \expandafter\POL@isolz@main
+ \fi
+}%
+\def\POL@initarray#1#2{%
+% ATTENTION, if only one item, \xintAssignArray UNBRACES IT
+% so we use an \empty trick to avoid that. Maybe considered a bug of xinttools?
+ \expandafter\xintAssignArray\expandafter\empty
+ \romannumeral\xintreplicate{\POL@isolz@NbOfRoots}{{#2}}\to#1%
+}%
+\def\POL@isolz@getsignchanges@plusinf{%
+ % Count number of sign changes at plus infinity in Sturm sequence
+ \def\POL@isolz@plusinf@SV{0}%
+ \edef\POL@isolz@lastsign{\xintiiSgn{\PolLeadingCoeff{\POL@sturmname _0}}}%
+ \let\POL@isolz@plusinf@sign\POL@isolz@lastsign
+ \POL@count\@ne
+ \xintloop
+ \edef\POL@isolz@newsign
+ {\xintiiSgn{\PolLeadingCoeff{\POL@sturmname _\the\POL@count}}}%
+ \unless\ifnum\POL@isolz@newsign=\POL@isolz@lastsign
+ \edef\POL@isolz@plusinf@SV{\the\numexpr\POL@isolz@plusinf@SV+\@ne}%
+ \fi
+ \let\POL@isolz@lastsign=\POL@isolz@newsign
+ \ifnum\POL@sturmlength>\POL@count
+ \advance\POL@count\@ne
+ \repeat
+}%
+\def\POL@isolz@getsignchanges@minusinf{%
+ % Count number of sign changes at minus infinity in Sturm sequence
+ \def\POL@isolz@minusinf@SV{0}%
+ \edef\POL@isolz@lastsign{\xintiiSgn{\PolLeadingCoeff{\POL@sturmname _0}}}%
+ \ifodd\PolDegree{\POL@sturmname _0}
+ \edef\POL@isolz@lastsign{\xintiiOpp{\POL@isolz@lastsign}}%
+ \fi
+ \let\POL@isolz@minusinf@sign\POL@isolz@lastsign
+ \POL@count\@ne
+ \xintloop
+ \edef\POL@isolz@newsign
+ {\xintiiSgn{\PolLeadingCoeff{\POL@sturmname _\the\POL@count}}}%
+ \ifodd\PolDegree{\POL@sturmname _\the\POL@count}
+ \edef\POL@isolz@newsign{\xintiiOpp{\POL@isolz@newsign}}%
+ \fi
+ \unless\ifnum\POL@isolz@newsign=\POL@isolz@lastsign
+ \edef\POL@isolz@minusinf@SV{\the\numexpr\POL@isolz@minusinf@SV+\@ne}%
+ \fi
+ \let\POL@isolz@lastsign=\POL@isolz@newsign
+ \ifnum\POL@sturmlength>\POL@count
+ \advance\POL@count\@ne
+ \repeat
+}%
+% utility macro for a priori bound on root decimal exponent, via Float Rounding
+\def\POL@isolz@updateE #1e#2;%
+ {\unless\ifnum#2<\POL@isolz@E\space\edef\POL@isolz@E{\the\numexpr#2+\@ne}\fi}%
+\def\POL@isolz@getaprioribound{%
+ \PolAssign{\POL@sturmname _0}\toarray\POL@arrayA
+ \edef\POL@isolz@leading{\POL@arrayA{\POL@arrayA{0}}}%
+ \POL@count\z@
+ \xintloop
+ \advance\POL@count\@ne
+ \ifnum\POL@arrayA{0}>\POL@count
+ \expandafter\edef\csname POL@arrayA\the\POL@count\endcsname
+ {\xintDiv{\POL@arrayA\POL@count}\POL@isolz@leading}%
+ \repeat
+ \def\POL@isolz@E{1}% WE SEEK SMALLEST E SUCH HAT -10^E < roots < +10^E
+ \advance\POL@count\m@ne
+ \xintloop
+ \ifnum\POL@count>\z@
+ \expandafter\POL@isolz@updateE
+ % use floating point to get decimal exponent
+ \romannumeral0\xintfloat[4]% should I use with [2] rather? (should work)
+ {\xintAdd{1/1[0]}{\xintAbs{\POL@arrayA\POL@count}}};%
+ \advance\POL@count\m@ne
+ \repeat
+ % \ifxintverbose\xintMessage{polexpr}{Info}%
+ % {Roots a priori bounded in absolute value by 10 to the \POL@isolz@E.}%
+ % \fi
+}%
+\def\POL@IsoRight@raw{\POL@IsoRight@Int/1[\POL@isolz@E]}%
+\def\POL@IsoLeft@raw {\POL@IsoLeft@Int/1[\POL@isolz@E]}%
+\def\POL@IsoRight@rawout{%
+ \ifnum\POL@IsoRightSign=\z@\expandafter\xintREZ\fi\POL@IsoRight@raw
+}%
+\def\POL@IsoLeft@rawout{%
+ \ifnum\POL@IsoRightSign=\z@
+ \expandafter\xint_firstoftwo\else\expandafter\xint_secondoftwo
+ \fi{\xintREZ\POL@IsoRight@raw}%
+ {\POL@IsoLeft@Int/1[\POL@isolz@E]}%
+}%
+\def\POL@isolz@main {%
+% NOTE 2018/02/16. THIS WILL PRESUMABLY BE RE-ORGANIZED IN FUTURE TO DO
+% FIRST POSITIVE ROOTS THEN NEGATIVE ROOTS VIA CHANGE OF VARIABLE TO OPPOSITE.
+ \global\POL@isolz@nextwillneedrefinefalse
+ \def\POL@IsoRight@Int{0}%
+ \POL@sturmchain@getSV@at\POL@IsoRight@raw
+ \let\POL@IsoRightSV \POL@sturmchain@SV
+ \let\POL@IsoRightSign\POL@sturmchain@sign
+ \let\POL@IsoAtZeroSV \POL@IsoRightSV
+ \let\POL@IsoAtZeroSign\POL@IsoRightSign
+ \ifnum\POL@IsoAtZeroSign=\z@
+ \xdef\POL@isolz@IntervalIndex
+ {\the\numexpr\POL@isolz@minusinf@SV-\POL@IsoRightSV}%
+ \POL@refine@storeleftandright % store zero root, \POL@IsoRightSign is zero
+ \edef\POL@IsoRightSV{\the\numexpr\POL@IsoRightSV+\@ne}%
+% subtlety here if original polynomial had multiplicities, but ok. I checked!
+ \edef\POL@IsoRightSign % evaluated twice, but that's not so bad
+ {\xintiiOpp{\xintiiSgn{\POL@eval{\POL@sturmname _1}{0/1[0]}}}}%
+ \fi
+ \def\POL@IsoLeft@Int{-1}% -10^E isn't a root!
+ \let\POL@IsoLeftSV \POL@isolz@minusinf@SV
+ \let\POL@IsoLeftSign\POL@isolz@minusinf@sign
+ % \POL@IsoRight@SV was modified if zero is a root
+ \edef\POL@isolz@NbOfNegRoots{\the\numexpr\POL@IsoLeftSV-\POL@IsoRightSV}%
+ \gdef\POL@isolz@IntervalIndex{0}%
+ \let\POL@isolz@@E\POL@isolz@E
+ \ifnum\POL@isolz@NbOfNegRoots>\z@
+% refactored at 0.7 to fix cases leading to an intervals with zero as end-point
+ \POL@isolz@findroots@neg
+ \fi
+ \let\POL@isolz@E\POL@isolz@@E
+ \def\POL@IsoLeft@Int{0}%
+ \let\POL@IsoLeftSV \POL@IsoAtZeroSV % véritable SV en zéro
+ \let\POL@IsoLeftSign\POL@IsoAtZeroSign% véritable signe en zéro
+ \ifnum\POL@IsoLeftSign=\z@
+ \xdef\POL@isolz@IntervalIndex{\the\numexpr\POL@isolz@IntervalIndex+\@ne}%
+ \fi
+ \let\POL@@IsoRightSV \POL@isolz@plusinf@SV
+ \let\POL@@IsoRightSign\POL@isolz@plusinf@sign % 10^E not a root!
+ \edef\POL@isolz@NbOfPosRoots
+ {\the\numexpr\POL@IsoLeftSV-\POL@@IsoRightSV}% attention @@
+ \ifnum\POL@isolz@NbOfPosRoots>\z@
+ % always do that to avoid zero as end-point whether it is a root or not
+ \global\POL@isolz@nextwillneedrefinetrue
+ \POL@isolz@findroots@pos
+ \fi
+}%
+\def\POL@isolz@findroots@neg{%
+ \def\POL@IsoRight@Int{-1}%
+ \POL@isolz@findnextzeroboundeddecade@neg
+ \def\POL@IsoLeft@Int{-10}%
+ \let\POL@@IsoRightSign\POL@IsoRightSign % a zero there is possible
+ \let\POL@@IsoRightSV \POL@IsoRightSV
+ % this will do possibly recursive \POL@isolz@check's
+ \POL@isolz@explorenexteightsubdecades@neg
+ \ifnum\POL@isolz@IntervalIndex<\POL@isolz@NbOfNegRoots\space
+ % above did not explore -2, -1 for this optimization (SV known at Right)
+ \def\POL@IsoRight@Int{-1}%
+ \let\POL@IsoRightSign\POL@@IsoRightSign
+ \let\POL@IsoRightSV \POL@@IsoRightSV
+ \POL@isolz@check
+ \ifnum\POL@isolz@IntervalIndex<\POL@isolz@NbOfNegRoots\space
+ \def\POL@IsoLeft@Int{-1}%
+ \let\POL@IsoLeftSign\POL@@IsoRightSign
+ \let\POL@IsoLeftSV \POL@@IsoRightSV
+ % I don't like being inside TeX conditionals
+ \expandafter\expandafter\expandafter\POL@isolz@findroots@neg
+ \fi
+ \fi
+}%
+\def\POL@isolz@findnextzeroboundeddecade@neg{%
+ \xintloop
+ \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}%
+ \POL@sturmchain@getSV@at\POL@IsoRight@raw
+ \let\POL@IsoRightSV \POL@sturmchain@SV
+ \let\POL@IsoRightSign\POL@sturmchain@sign
+ % would an \ifx test be quicker? (to be checked)
+ \ifnum\POL@IsoRightSV=\POL@IsoLeftSV\space
+ % no roots in-between, iterate
+ \repeat
+}%
+\def\POL@isolz@explorenexteightsubdecades@neg{%
+ \xintloop
+ \edef\POL@IsoRight@Int{\the\numexpr\POL@IsoLeft@Int+\@ne}%
+ % we could arguably do a more efficient dichotomy here
+ \POL@sturmchain@getSV@at\POL@IsoRight@raw
+ \let\POL@IsoRightSV \POL@sturmchain@SV
+ \let\POL@IsoRightSign\POL@sturmchain@sign
+ \POL@isolz@check % may recurse if multiple roots are to be found
+ \ifnum\POL@isolz@IntervalIndex=\POL@isolz@NbOfNegRoots\space
+ \expandafter\xintbreakloop
+ \fi
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int
+ \let\POL@IsoLeftSign\POL@IsoRightSign
+ \let\POL@IsoLeftSV\POL@IsoRightSV
+ \ifnum\POL@IsoRight@Int < -\tw@
+ \repeat
+}%
+\def\POL@isolz@findroots@pos{%
+ % remark (2018/12/08), this needs some refactoring, I hardly understand
+ % the logic and it hides most into the recursion done by \POL@isolz@check
+ % It would probably make more sense to proceed like done for the negative
+ % but here finding the largest roots first.
+ \def\POL@IsoRight@Int{1}%
+ \POL@isolz@findnextzeroboundeddecade@pos
+ \unless\ifnum\POL@IsoRightSV=\POL@IsoLeftSV\space
+ % this actually explores the whole of some interval (0, 10^{e-1}]
+ % in a context where some roots are known to be in (10^{e-1}, 10^{e}]
+ % and none are larger
+ \POL@isolz@check % will recurse inside groups if needed with modified E
+ \fi
+ % we know get the roots in the last 9 decades from 10^{e-1} to 10^{e}
+ % we should arguably do a more efficient dichotomy here
+ \def\POL@IsoLeft@Int{1}%
+ \let\POL@IsoLeftSV\POL@IsoRightSV
+ \let\POL@IsoLeftSign\POL@IsoRightSign
+ \xintloop
+ \edef\POL@IsoRight@Int{\the\numexpr\POL@IsoLeft@Int+\@ne}%
+ \POL@sturmchain@getSV@at\POL@IsoRight@raw
+ \let\POL@IsoRightSV \POL@sturmchain@SV
+ \let\POL@IsoRightSign\POL@sturmchain@sign
+ \POL@isolz@check % recurses in needed
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int
+ \let\POL@IsoLeftSign\POL@IsoRightSign
+ \let\POL@IsoLeftSV\POL@IsoRightSV
+ \ifnum\POL@isolz@IntervalIndex=\POL@isolz@NbOfRoots\space
+ \expandafter\xintbreakloop
+ \fi
+ \ifnum\POL@IsoLeft@Int < \xint_c_ix
+ \repeat
+ \ifnum\POL@isolz@IntervalIndex<\POL@isolz@NbOfRoots\space
+ % get now the last, rightmost, root (or roots)
+ \def\POL@IsoRight@Int{10}%
+ \let\POL@IsoRightSign\POL@@IsoRightSign
+ \let\POL@IsoRightSV\POL@@IsoRightSV
+ \POL@isolz@check
+ \fi
+}%
+\def\POL@isolz@findnextzeroboundeddecade@pos{%
+ \xintloop
+ \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}%
+ \POL@sturmchain@getSV@at\POL@IsoRight@raw
+ \let\POL@IsoRightSV \POL@sturmchain@SV
+ \let\POL@IsoRightSign\POL@sturmchain@sign
+ \ifnum\POL@IsoRightSV=\POL@@IsoRightSV\space
+ \let\POL@@IsoRightSign\POL@IsoRightSign % root here possible!
+ \repeat
+}%
+\def\POL@isolz@check{% \POL@IsoRightSign must be ready for use here
+% \ifxintverbose
+% \xintMessage{polexpr}{Info}%
+% {\the\numexpr\POL@IsoLeftSV-\POL@IsoRightSV\relax\space roots
+% in (\POL@IsoLeft@raw,\POL@IsoRight@raw] (E = \POL@isolz@E)}%
+% \fi
+ \ifcase\numexpr\POL@IsoLeftSV-\POL@IsoRightSV\relax
+ % no root in ]left, right]
+ \global\POL@isolz@nextwillneedrefinefalse
+ \or
+ % exactly one root in ]left, right]
+ \xdef\POL@isolz@IntervalIndex{\the\numexpr\POL@isolz@IntervalIndex+\@ne}%
+ \ifnum\POL@IsoRightSign=\z@
+ % if right boundary is a root, ignore previous flag
+ \global\POL@isolz@nextwillneedrefinefalse
+ \fi
+ % if left boundary is known to have been a root we refine interval
+ \ifPOL@isolz@nextwillneedrefine
+ \expandafter\expandafter\expandafter\POL@isolz@refine
+ \else
+ % \POL@IsoRightSign is zero iff root now exactly known
+ \POL@refine@storeleftandright
+ \ifnum\POL@IsoRightSign=\z@
+ \global\POL@isolz@nextwillneedrefinetrue
+ \fi
+ \fi
+ \else
+ % more than one root, we need to recurse
+ \expandafter\POL@isolz@recursedeeper
+ \fi
+}%
+\def\POL@isolz@recursedeeper{%
+% NOTE 2018/02/16. I SHOULD DO A REAL BINARY DICHOTOMY HERE WHICH ON AVERAGE
+% SHOULD BRING SOME GAIN (LIKE WHAT IS ALREADY DONE FOR THE "refine" MACROS.
+% THUS IN FUTURE THIS MIGHT BE REFACTORED.
+\begingroup
+ \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}%
+ \edef\POL@@IsoRight@Int{\xintDSL{\POL@IsoRight@Int}}%
+ \let\POL@@IsoRightSign \POL@IsoRightSign
+ \let\POL@@IsoRightSV \POL@IsoRightSV
+ \edef\POL@IsoLeft@Int {\xintDSL{\POL@IsoLeft@Int}}%
+ \xintiloop[1+1]
+ \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}%
+ \POL@sturmchain@getSV@at\POL@IsoRight@raw
+ \let\POL@IsoRightSV \POL@sturmchain@SV
+ \let\POL@IsoRightSign\POL@sturmchain@sign
+ \POL@isolz@check
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int
+ \let\POL@IsoLeftSV\POL@IsoRightSV
+ \let\POL@IsoLeftSign\POL@IsoRightSign% not used, actually
+ \ifnum\POL@IsoLeftSV=\POL@@IsoRightSV\space
+ \expandafter\xintbreakiloop
+ \fi
+ \ifnum\xintiloopindex < \xint_c_ix
+ \repeat
+ \let\POL@IsoRight@Int\POL@@IsoRight@Int
+ \let\POL@IsoRightSign\POL@@IsoRightSign
+ \let\POL@IsoRightSV \POL@@IsoRightSV
+ % if we exited the loop via breakiloop this is superfluous
+ % but it only costs one \ifnum
+ \POL@isolz@check
+\endgroup
+}%
+\def\POL@isolz@refine{%
+ % starting point is first root = left < unique second root < right
+ % even if we hit exactly via refinement second root, we set flag false as
+ % processing will continue with original right end-point, which isn't a root
+ \global\POL@isolz@nextwillneedrefinefalse
+\begingroup
+ \let\POL@@IsoRightSign\POL@IsoRightSign % already evaluated
+ \xintloop
+ \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}%
+ \edef\POL@IsoLeft@Int {\xintDSL{\POL@IsoLeft@Int}}%
+ \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}%
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\POL@@IsoRightSign\space
+ \repeat
+ % now second root has been separated from the one at left end point
+% we update the storage of the root at left for it to have the same number
+% of digits in mantissa. No, I decided not to do that to avoid complications.
+ % \begingroup
+ % \let\POL@IsoRight@Int\POL@IsoLeft@Int
+ % \def\POL@IsoRightSign{0}%
+ % \edef\POL@isolz@IntervalIndex{\the\numexpr\POL@isolz@IntervalIndex-\@ne}%
+ % \POL@refine@storeleftandright
+ % \endgroup
+ \edef\POL@@IsoRight@Int{\xintDSL{\xintInc{\xintDSR{\POL@IsoLeft@Int}}}}%
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int
+ \let\POL@IsoLeftSign\POL@IsoRightSign
+ \ifnum\POL@IsoRightSign=\z@ % check if new Left is actually a root
+ \else
+ \edef\POL@IsoRight@Int{\xintDec{\POL@@IsoRight@Int}}%
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\POL@@IsoRightSign\space
+ \POL@refine@doonce % we need to locate in interval (1, 9) in local scale
+ \else
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int
+ \ifnum\POL@IsoRightSign=\z@
+ \def\POL@IsoLeftSign{0}%
+ \else
+ \let\POL@IsoRight@Int\POL@@IsoRight@Int
+ % the IsoRightSign is now wrong but here we don't care
+ \fi\fi
+ \fi
+ % on exit, exact root found iff \POL@IsoRightSign is zero
+ \POL@refine@storeleftandright
+\endgroup
+}%
+\def\POL@refine@doonce{% if exact root is found, always in IsoRight on exit
+% NOTE: FUTURE REFACTORING WILL GET RID OF \xintiiAdd WHICH ARE A BIT COSTLY
+% BUT BASICALLY NEEDED TO HANDLE BOTH NEGATIVE AND POSITIVE HERE.
+% I WILL RE-ORGANIZE THE WHOLE THING IN FUTURE TO GET ROOTS STARTING FROM
+% THE ORIGIN AND SIMPLY RE-LABEL THE NEGATIVE ONE AT THE END. 2018/02/16.
+ \let\POL@@IsoRight@Int\POL@IsoRight@Int % 9
+ \let\POL@@IsoRightSign\POL@IsoRightSign
+ \edef\POL@IsoRight@Int{\xintiiAdd{4}{\POL@IsoLeft@Int}}% 5
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % 5
+ \edef\POL@IsoRight@Int{\xintiiAdd{2}{\POL@IsoLeft@Int}}%
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % 7
+ \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}%
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % 8
+ \let\POL@IsoRight@Int\POL@@IsoRight@Int % 9
+ \let\POL@IsoRightSign\POL@@IsoRightSign % opposite of one at left
+ \fi % else 7, 8 with possible root at 8
+ \else
+ \ifnum\POL@IsoRightSign=\z@
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % root at 7
+ \def\POL@IsoLeftSign{0}%
+ \else
+ \let\POL@@IsoRight@Int\POL@IsoRight@Int % 7
+ \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% 6
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % 6
+ \let\POL@IsoRight@Int\POL@@IsoRight@Int % 7
+ \let\POL@IsoRightSign\POL@@IsoRightSign
+ \fi % else 5, 6 with possible root at 6
+ \fi\fi
+ \else
+ \ifnum\POL@IsoRightSign=\z@
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % root at 5
+ \def\POL@IsoLeftSign{0}%
+ \else
+ \let\POL@@IsoRight@Int\POL@IsoRight@Int % 5
+ \edef\POL@IsoRight@Int{\xintiiAdd{2}{\POL@IsoLeft@Int}}%
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % 3
+ \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% 4
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % 4
+ \let\POL@IsoRight@Int\POL@@IsoRight@Int % 5
+ \let\POL@IsoRightSign\POL@@IsoRightSign
+ \fi % else 3, 4 with possible root at 4
+ \else
+ \ifnum\POL@IsoRightSign=\z@
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % root at 3
+ \def\POL@IsoLeftSign{0}%
+ \else
+ \let\POL@@IsoRight@Int\POL@IsoRight@Int % 3
+ \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}% 2
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\POL@IsoLeftSign\space
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % 2
+ \let\POL@IsoRight@Int\POL@@IsoRight@Int % 3
+ \let\POL@IsoRightSign\POL@@IsoRightSign
+ \fi % else 1, 2 with possible root at 2
+ \fi\fi
+ \fi\fi
+}%
+\def\POL@refine@storeleftandright{%
+ \expandafter
+ \xdef\csname POL_ZL\POL@sturmname*\POL@isolz@IntervalIndex\endcsname
+ {\PolDecToString{\POL@IsoLeft@rawout}}%
+ \expandafter
+ \xdef\csname POL_ZR\POL@sturmname*\POL@isolz@IntervalIndex\endcsname
+ {\PolDecToString{\POL@IsoRight@rawout}}%
+ % added at 0.6
+ \ifnum\POL@IsoRightSign=\z@
+ \global
+ \expandafter
+ \let\csname POL_ZK\POL@sturmname*\POL@isolz@IntervalIndex\endcsname
+ \xint_stop_atfirstoftwo
+ \fi
+ \begingroup\xintglobaldefstrue
+ % skip some overhead of \xintdefvar...
+ \XINT_expr_defvar_one{\POL@sturmname L_\POL@isolz@IntervalIndex}%
+ {\csname .=\POL@IsoLeft@rawout\endcsname}%
+ \XINT_expr_defvar_one{\POL@sturmname R_\POL@isolz@IntervalIndex}%
+ {\csname .=\POL@IsoRight@rawout\endcsname}%
+ % added at 0.7
+ \XINT_expr_defvar_one{\POL@sturmname Z_\POL@isolz@IntervalIndex _isknown}%
+ {\csname .=\ifnum\POL@IsoRightSign=\z@ 1\else 0\fi\endcsname}%
+ \endgroup
+}%
+%% \PolRefineInterval
+\def\POL@xintexprGetVar#1{\expandafter\expandafter\expandafter
+ \XINT_expr_unlock\csname XINT_expr_var_#1\endcsname}%
+% attention, also used by \POL@findrat@loop@a
+\def\POL@get@IsoLeft@rawin{%
+ \edef\POL@IsoLeft@rawin
+ {\POL@xintexprGetVar{\POL@sturmname L_\POL@isolz@IntervalIndex}}%
+}%
+% attention, also used by \POL@findrat@loop@a
+\def\POL@get@IsoRight@rawin{%
+ \edef\POL@IsoRight@rawin
+ {\POL@xintexprGetVar{\POL@sturmname R_\POL@isolz@IntervalIndex}}%
+}%
+% attention, also used by \POL@findrat@loop@a
+\def\POL@get@Int@aux #1/1[#2]#3#4{\edef#3{\xintDSH{#4-#2}{#1}}}%
+\def\POL@get@IsoLeft@Int{%
+ \expandafter\POL@get@Int@aux\POL@IsoLeft@rawin\POL@IsoLeft@Int\POL@isolz@E
+}%
+\newcommand\PolRefineInterval{\@ifstar\POL@srefine@start\POL@refine@start}%
+\newcommand\POL@refine@start[3][1]{%
+ \edef\POL@isolz@IntervalIndex{\the\numexpr#3}%
+ \edef\POL@sturmname{#2}%
+ \expandafter\POL@refine@sharedbody\expandafter
+ {\expandafter\POL@refine@loop\expandafter{\the\numexpr#1}}%
+}%
+\def\POL@srefine@start#1#2{%
+ \edef\POL@isolz@IntervalIndex{\the\numexpr#2}%
+ \edef\POL@sturmname{#1}%
+ \POL@refine@sharedbody
+ {\let\POL@refine@left@next\POL@refine@main % we want to recurse if needed
+ \let\POL@refine@right@next\POL@refine@main % we want to recurse if needed
+ \POL@refine@main}%
+}%
+\def\POL@refine@sharedbody#1{%
+ \POL@get@IsoLeft@rawin
+ \edef\POL@IsoLeftSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoLeft@rawin}}}%
+ \ifnum\POL@IsoLeftSign=\z@
+ % do nothing if that interval was already a singleton
+ \else
+ % else both end-points are not roots and there is a single one in-between
+ \POL@get@IsoRight@rawin
+ \edef\POL@IsoRightSign{\the\numexpr-\POL@IsoLeftSign}%
+ \edef\POL@isolz@E{\expandafter\POL@refine@getE
+ % je pense que le xintrez ici est superflu
+ \romannumeral0\xintrez{\xintSub{\POL@IsoRight@rawin}{\POL@IsoLeft@rawin}}}%
+ \POL@get@IsoLeft@Int
+ \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}%
+ #1%
+ \POL@refine@storeleftandright % \POL@IsoRightSign not zero
+ \fi
+}%
+\def\POL@refine@loop#1{%
+ \let\POL@refine@left@next \@empty % no recursion at end sub-intervals
+ \let\POL@refine@right@next\@empty
+ \xintiloop[1+1]
+ \POL@refine@main
+ \ifnum\POL@IsoRightSign=\z@
+ \expandafter\xintbreakiloop
+ \fi
+ \ifnum\xintiloopindex<#1
+ \repeat
+}%
+\def\POL@refine@main{%
+ \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}%
+ \edef\POL@IsoLeft@Int{\xintDSL{\POL@IsoLeft@Int}}%
+ \edef\POL@IsoRight@Int{\xintDSL{\POL@IsoRight@Int}}%
+ \let\POL@@IsoRight@Int\POL@IsoRight@Int
+ \let\POL@@IsoRightSign\POL@IsoRightSign
+ \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}%
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\z@
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % root at 1
+ \def\POL@IsoLeftSign{0}%
+ \let\POL@next\@empty
+ \else
+ \ifnum\POL@IsoRightSign=\POL@@IsoRightSign\space
+ \let\POL@next\POL@refine@left@next % may be \@empty or \POL@refine@main for recursion
+ \let\POL@refine@right@next\@empty
+ \else
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int
+ \edef\POL@IsoRight@Int{\xintDec{\POL@@IsoRight@Int}}%
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ \ifnum\POL@IsoRightSign=\z@
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int % root at 9
+ \def\POL@IsoLeftSign{0}%
+ \let\POL@next\@empty
+ \else
+ \ifnum\POL@IsoRightSign=\POL@@IsoRightSign\space
+ \let\POL@next\POL@refine@doonce
+ \else
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int
+ \let\POL@IsoRight@Int\POL@@IsoRight@Int
+ \let\POL@IsoRightSign\POL@@IsoRightSign
+ \let\POL@next\POL@refine@right@next
+ \let\POL@refine@left@next\@empty
+ \fi
+ \fi
+ \fi\fi
+ \POL@next
+}%
+% lacking pre-defined xintfrac macro here (such as an \xintRawExponent)
+\def\POL@refine@getE#1[#2]{#2}% \xintREZ already applied, for safety
+
+
+\newcommand\PolIntervalWidth[2]{%
+% le \xintRez est à cause des E positifs, car trailing zéros explicites
+% si je travaillais à partir des variables xintexpr directement ne devrait
+% pas être nécessaire, mais trop fragile par rapport à chgt internes possibles
+ \romannumeral0\xintrez{\xintSub{\@nameuse{POL_ZR#1*}{#2}}%
+ {\@nameuse{POL_ZL#1*}{#2}}}
+}%
+
+
+\newcommand\PolEnsureIntervalLengths[2]{% #1 = Sturm chain name,
+ % localize roots in intervals of length at most 10^{#2}
+ \edef\POL@sturmname{#1}%
+ \edef\POL@ensure@targetE{\the\numexpr#2}%
+ \edef\POL@nbofroots{\csname POL_ZL\POL@sturmname*0\endcsname}%
+ \ifnum\POL@nbofroots>\z@
+ \expandafter\POL@ensureintervallengths
+ \fi
+}%
+\def\POL@ensureintervallengths{%
+ \POL@count\z@
+ % \POL@count used by \POL@sturmchain@getSV@at but latter not used
+ \xintloop
+ \advance\POL@count\@ne
+ \edef\POL@isolz@IntervalIndex{\the\POL@count}%
+ \POL@ensure@one
+ \ifnum\POL@nbofroots>\POL@count
+ \repeat
+}%
+\newcommand\PolEnsureIntervalLength[3]{% #1 = Sturm chain name,
+ % #2 = index of interval
+ % localize roots in intervals of length at most 10^{#3}
+ \edef\POL@sturmname{#1}%
+ \edef\POL@ensure@targetE{\the\numexpr#3}%
+ \edef\POL@isolz@IntervalIndex{\the\numexpr#2}%
+% peut-être autoriser -1, -2, ... ?
+ \ifnum\POL@isolz@IntervalIndex>\z@
+% 0.7, add this safeguard but attention means this structure must be in place
+ \ifnum\csname POL_ZL\POL@sturmname*0\endcsname>\z@
+% je ne fais pas les \expandafter mais je préfèrerai ne pas être à l'intérieur
+ \POL@ensure@one
+ \fi
+ \fi
+}%
+\def\POL@ensure@one{%
+ \POL@get@IsoLeft@rawin
+ \POL@get@IsoRight@rawin
+ \edef\POL@ensure@delta{\xintREZ{\xintSub{\POL@IsoRight@rawin}{\POL@IsoLeft@rawin}}}%
+ \xintiiifZero{\POL@ensure@delta}
+ {}
+ {\edef\POL@isolz@E{\expandafter\POL@refine@getE\POL@ensure@delta}%
+ \POL@get@IsoLeft@Int
+ \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}%
+ \ifnum\POL@isolz@E>\POL@ensure@targetE\space
+ \edef\POL@IsoLeftSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoLeft@raw}}}%
+ % at start left and right are not roots, and values of opposite signs
+ % \edef\POL@IsoRightSign{\the\numexpr-\POL@IsoLeftSign}%
+ \xintloop
+ \POL@ensure@Eloopbody % decreases E by one at each iteration
+ % if separation level is still too coarse we recurse at deeper level
+ \ifnum\POL@isolz@E>\POL@ensure@targetE\space
+ \repeat
+ % will check if right is at a zero, it needs \POL@IsoRightSign set up
+ \POL@refine@storeleftandright
+ \fi
+ }%
+}%
+\def\POL@ensure@Eloopbody {%
+ \edef\POL@isolz@E{\the\numexpr\POL@isolz@E-\@ne}%
+ \edef\POL@IsoLeft@Int{\xintDSL{\POL@IsoLeft@Int}}%
+ % this will loop at most ten times
+ \xintloop
+ \edef\POL@IsoRight@Int{\xintInc{\POL@IsoLeft@Int}}%
+ \edef\POL@IsoRightSign
+ {\xintiiSgn{\POL@eval{\POL@sturmname _0}{\POL@IsoRight@raw}}}%
+ % if we have found a zero at right boundary the \ifnum test will fail
+ % and we exit the loop
+ % else we exit the loop if sign at right boundary is opposite of
+ % sign at left boundary (the latter is +1 or -1, never 0)
+ % this is a bit wasteful if we go ten times to the right, because
+ % we know that there the sign will be opposite, evaluation was superfluous
+ \ifnum\POL@IsoLeftSign=\POL@IsoRightSign\space
+ \let\POL@IsoLeft@Int\POL@IsoRight@Int
+ \repeat
+ % check for case when we exited the inner loop because we actually
+ % found a zero, then we force exit from the main (E decreasing) loop
+ \ifnum\POL@IsoRightSign=\z@
+ \expandafter\xintbreakloop
+ \fi
+}%
+
+
+\catcode`_ 8
+\newcommand\PolPrintIntervals
+ {\@ifstar{\PolPrintIntervals@@}{\PolPrintIntervals@}}%
+\newcommand\PolPrintIntervals@@{%
+ \begingroup
+ \def\POL@AfterPrintIntervals{\endgroup}%
+ \def\arraystretch{2}%
+ \let\PolPrintIntervalsPrintExactZero\POL@@PrintIntervalsPrintExactZero
+ \let\PolPrintIntervalsUnknownRoot\POL@@PrintIntervalsUnknownRoot
+ \let\PolPrintIntervalsKnownRoot\POL@@PrintIntervalsKnownRoot
+ \def\PolPrintIntervalsBeginEnv{\[\begin{array}{cl}}%\]
+ \def\PolPrintIntervalsEndEnv{\end{array}\]}%
+ \PolPrintIntervals@
+}%
+\newcommand\PolPrintIntervals@[2][Z]{\POL@PrintIntervals{#1}{#2}}%
+\newcommand\POL@PrintIntervals[2]{%
+ \def\PolPrintIntervalsTheVar{#1}%
+ \def\PolPrintIntervalsTheSturmName{#2}%
+ \ifnum\@nameuse{POL_ZL#2*}{0}=\z@
+ \PolPrintIntervalsNoRealRoots
+ \else
+ \gdef\PolPrintIntervalsTheIndex{1}%
+ \POL@PrintIntervals@DoDefs
+ \begingroup\edef\POL@tmp{\endgroup
+ \unexpanded\expandafter{\PolPrintIntervalsBeginEnv}%
+ \unexpanded\expandafter{\POL@PrintIntervals@Loop}%
+ \unexpanded\expandafter{\PolPrintIntervalsEndEnv}%
+ }\POL@tmp
+ \fi
+ \POL@AfterPrintIntervals
+ \def\PolPrintIntervalsTheVar{#1}%
+ \def\PolPrintIntervalsTheSturmName{#2}%
+}%
+\let\POL@AfterPrintIntervals\@empty
+\newcommand\PolPrintIntervalsNoRealRoots{}%
+\newcommand\PolPrintIntervalsBeginEnv{\[\begin{array}{rcccl}}%
+\newcommand\PolPrintIntervalsEndEnv{\end{array}\]}%
+\newcommand\PolPrintIntervalsKnownRoot{%
+ &&\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}%
+ &=&\PolPrintIntervalsPrintExactZero
+}%
+\newcommand\PolPrintIntervalsUnknownRoot{%
+ \PolPrintIntervalsPrintLeftEndPoint&<&%
+ \PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}&<&%
+ \PolPrintIntervalsPrintRightEndPoint
+}%
+\newcommand\PolPrintIntervalsPrintExactZero {\PolPrintIntervalsTheLeftEndPoint}%
+\newcommand\PolPrintIntervalsPrintLeftEndPoint {\PolPrintIntervalsTheLeftEndPoint}%
+\newcommand\PolPrintIntervalsPrintRightEndPoint{\PolPrintIntervalsTheRightEndPoint}%
+\newcommand\PolPrintIntervalsPrintMultiplicity{(\mbox{mult. }\PolPrintIntervalsTheMultiplicity)}%
+%
+\newcommand\POL@@PrintIntervalsKnownRoot{%
+ \PolPrintIntervalsPrintMultiplicity&%
+ \PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}=%
+ \PolPrintIntervalsPrintExactZero
+}%
+\newcommand\POL@@PrintIntervalsPrintExactZero{%
+ \displaystyle
+ \xintSignedFrac{\PolPrintIntervalsTheLeftEndPoint}%
+}%
+\newcommand\POL@@PrintIntervalsUnknownRoot{%
+ \PolPrintIntervalsPrintMultiplicity&%
+ \xintifSgn{\PolPrintIntervalsTheLeftEndPoint}%
+ {\xintifSgn{\PolPrintIntervalsTheRightEndPoint}
+ {\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}=%
+ \PolPrintIntervalsPrintRightEndPoint\dots}%
+ {0>\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}>%
+ \PolPrintIntervalsPrintLeftEndPoint}%
+ {\PolErrorThisShouldNotHappenPleaseReportToAuthorA}}%
+ {\xintifSgn{\PolPrintIntervalsTheRightEndPoint}
+ {\PolErrorThisShouldNotHappenPleaseReportToAuthorB}%
+ {\PolErrorThisShouldNotHappenPleaseReportToAuthorC}%
+ {0<\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}<%
+ \PolPrintIntervalsPrintRightEndPoint}}%
+ {\xintifSgn{\PolPrintIntervalsTheRightEndPoint}
+ {\PolErrorThisShouldNotHappenPleaseReportToAuthorD}%
+ {\PolErrorThisShouldNotHappenPleaseReportToAuthorE}%
+ {\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}=%
+ \PolPrintIntervalsPrintLeftEndPoint\dots}}%
+}%
+%
+\catcode`_ 11
+\def\POL@PrintIntervals@Loop{%
+ \POL@SturmIfZeroExactlyKnown\PolPrintIntervalsTheSturmName
+ \PolPrintIntervalsTheIndex
+ \PolPrintIntervalsKnownRoot
+ \PolPrintIntervalsUnknownRoot
+ \xdef\PolPrintIntervalsTheIndex{\the\numexpr\PolPrintIntervalsTheIndex+\@ne}%
+ \unless\ifnum\PolPrintIntervalsTheIndex>
+ \@nameuse{POL_ZL\PolPrintIntervalsTheSturmName*0}
+ \POL@PrintIntervals@DoDefs
+ \xint_afterfi{\\\POL@PrintIntervals@Loop}%
+ \fi
+}%
+\def\POL@PrintIntervals@DoDefs{%
+ \xdef\PolPrintIntervalsTheLeftEndPoint{%
+ \csname POL_ZL\PolPrintIntervalsTheSturmName*\PolPrintIntervalsTheIndex
+ \endcsname
+ }%
+ \xdef\PolPrintIntervalsTheRightEndPoint{%
+ \csname POL_ZR\PolPrintIntervalsTheSturmName*\PolPrintIntervalsTheIndex
+ \endcsname
+ }%
+ \xdef\PolPrintIntervalsTheMultiplicity{%
+ \ifcsname POL_ZM\PolPrintIntervalsTheSturmName*\PolPrintIntervalsTheIndex
+ \endcsname
+ \csname POL_ZM\PolPrintIntervalsTheSturmName*\PolPrintIntervalsTheIndex
+ \endcsname
+ \else
+ ?% or use 0 ?
+ \fi
+ }%
+}%
+
+
+\newcommand\PolSturmIfZeroExactlyKnown[2]{% #1 = sturmname, #2=index
+ \romannumeral0\csname POL_ZK#1*\endcsname{#2}%
+}%
+\newcommand\POL@SturmIfZeroExactlyKnown[2]{% #1 = sturmname, #2=index
+ \romannumeral0\csname POL_ZK#1*\the\numexpr#2\endcsname
+}%
+\newcommand\PolSturmIsolatedZeroMultiplicity[2]{%
+ \romannumeral`^^@\csname POL_ZM#1*\endcsname{#2}%
+}%
+\newcommand\PolSturmIsolatedZeroLeft[2]{%
+ \romannumeral`^^@\csname POL_ZL#1*\endcsname{#2}%
+}%
+\newcommand\PolSturmIsolatedZeroRight[2]{%
+ \romannumeral`^^@\csname POL_ZR#1*\endcsname{#2}%
+}%
+\newcommand\PolSturmNbOfIsolatedZeros[1]{%
+ \romannumeral`^^@\csname POL_ZL#1*0\endcsname
+}%
+\newcommand\PolSturmRationalRoot[2]{%
+ \romannumeral`^^@\csname POL_ZL#1*%
+ \csname POL_RI#1*\endcsname{#2}\endcsname
+}%
+\newcommand\PolSturmRationalRootIndex[2]{%
+ \romannumeral`^^@\csname POL_RI#1*\endcsname{#2}%
+}%
+\newcommand\PolSturmRationalRootMultiplicity[2]{%
+ \romannumeral`^^@\csname POL_ZM#1%
+ *\csname POL_RI#1*\endcsname{#2}\endcsname
+}%
+\newcommand\PolSturmNbOfRationalRoots[1]{%
+ \romannumeral`^^@\csname POL_RI#1*0\endcsname
+}%
+\newcommand\PolSturmNbOfRationalRootsWithMultiplicities[1]{%
+% means the \POL@norr must not have been changed in-between...
+ \the\numexpr\PolDegree{#1}-\PolDegree{#1\POL@norr}\relax
+}%
+
+
+\let\PolDecToString\xintDecToString
+
+
+\newcommand\PolMakeMonic[1]{%
+ \edef\POL@leadingcoeff{\PolLeadingCoeff{#1}}%
+ \edef\POL@leadingcoeff@inverse{\xintDiv{1/1[0]}{\POL@leadingcoeff}}%
+ \PolMapCoeffs{\xintMul{\POL@leadingcoeff@inverse}}{#1}%
+}%
+
+
+%% CORE ALGEBRA MACROS
+%% We do this non-expandably, but in a nestable way... this is the whole
+%% point because \xintdeffunc as used by \poldef creates a big nested macro.
+%% The idea is to execute it with another meaning given to \xintAdd etc..,
+%% so that it operates on "polynomials". This is a mixture of expandable
+%% and non-expandable techniques.
+\def\POL@get#1#2#3{%
+ \global\POL@polfalse
+ \begingroup
+ \def\POL@result{#3}%
+ #3%
+ \expandafter
+ \endgroup
+ \expandafter\def\expandafter#1\expandafter{\POL@result}%
+ \unless\ifPOL@pol
+ % avoid expanding more than twice #3
+ \edef#1{#3}%
+ \xintiiifZero{#1}%
+ {\def#1{-1.\empty{0/1[0]}}}%
+ {\edef#1{0.\noexpand\empty{#1}}}%
+ \fi
+ #2%
+}%
+%% ADDITION
+\def\POL@add {\POL@get\POL@A\POL@add@b}%
+\def\POL@add@b{\POL@get\POL@B\POL@add@c}%
+\def\POL@add@c{%
+ \global\POL@poltrue
+ \POL@ifZero\POL@A
+ {\let\POL@result\POL@B}%
+ {\POL@ifZero\POL@B
+ {\let\POL@result\POL@A}%
+ {\POL@@add}}%
+}%
+\def\POL@@add{%
+ \expandafter\POL@split\POL@A;\POL@degA\POL@polA
+ \expandafter\POL@split\POL@B;\POL@degB\POL@polB
+ \ifnum\POL@degA>\POL@degB\relax
+ \xintAssignArray\POL@polA\to\POL@arrayA
+ \xintAssignArray\POL@polB\to\POL@arrayB
+ \else
+ \xintAssignArray\POL@polB\to\POL@arrayA
+ \xintAssignArray\POL@polA\to\POL@arrayB
+ \let\POL@tmp\POL@degB\let\POL@degB\POL@degA\let\POL@degA\POL@tmp
+ \fi
+ \count@\z@
+ \xintloop
+ \advance\count@\@ne
+ \expandafter\edef\csname POL@arrayA\the\count@\endcsname
+ {\xintScalarAdd{\@nameuse{POL@arrayA\the\count@}}%
+ {\@nameuse{POL@arrayB\the\count@}}}%
+ \unless\ifnum\POL@degB<\count@
+ \repeat
+ \count@\@nameuse{POL@arrayA0} % 1+\POL@degA
+ % trim zero leading coefficients (we could check for equal degrees,
+ % but would not bring much as anyhow loop exists immediately if not)
+ \xintloop
+ % this abuses that \POL@arrayA0 is never zero
+ \xintiiifZero{\@nameuse{POL@arrayA\the\count@}}%
+ {\iftrue}%
+ {\iffalse}%
+ \advance\count@\m@ne
+ \repeat
+ \POL@resultfromarray A% attention that \POL@arrayA0 not updated
+}%
+
+%% MULTIPLICATION
+\def\POL@mul {\POL@get\POL@A\POL@mul@b}%
+\def\POL@mul@b{\POL@get\POL@B\POL@mul@c}%
+\def\POL@mul@c{%
+ \global\POL@poltrue
+ \POL@ifZero\POL@A
+ {\def\POL@result{-1.\empty{0/1[0]}}}%
+ {\POL@ifZero\POL@B
+ {\def\POL@result{-1.\empty{0/1[0]}}}%
+ {\POL@@mul}}%
+}%
+\def\POL@@mul{%
+ \expandafter\POL@split\POL@A;\POL@degA\POL@polA
+ \expandafter\POL@split\POL@B;\POL@degB\POL@polB
+ \ifnum\POL@degA>\POL@degB\relax
+ \xintAssignArray\POL@polA\to\POL@arrayA
+ \xintAssignArray\POL@polB\to\POL@arrayB
+ \else
+ \xintAssignArray\POL@polB\to\POL@arrayA
+ \xintAssignArray\POL@polA\to\POL@arrayB
+ \let\POL@tmp\POL@degB
+ \let\POL@degB\POL@degA
+ \let\POL@degA\POL@tmp
+ \fi
+ \count@\z@
+ \xintloop
+ \POL@@mul@phaseIloopbody
+ \unless\ifnum\POL@degB<\count@
+ \repeat
+ \xintloop
+ \unless\ifnum\POL@degA<\count@ % car attention au cas de mêmes degrés
+ \POL@@mul@phaseIIloopbody
+ \repeat
+ \edef\POL@degC{\the\numexpr\POL@degA+\POL@degB}%
+ \xintloop
+ \unless\ifnum\POL@degC<\count@
+ \POL@@mul@phaseIIIloopbody
+ \repeat
+ %\count@\the\numexpr\POL@degC+\@ne\relax % never zero polynomial here
+ \POL@resultfromarray C%
+}%
+\def\POL@@mul@phaseIloopbody{%
+ \advance\count@\@ne
+ \def\POL@tmp{0[0]}%
+ \count\tw@\z@
+ \xintloop
+ \advance\count\tw@\@ne
+ \edef\POL@tmp{%
+ \xintScalarAdd
+ {\POL@tmp}%
+ {\xintScalarMul
+ {\@nameuse{POL@arrayA\the\count\tw@}}%
+ {\@nameuse{POL@arrayB\the\numexpr\count@+\@ne-\count\tw@}}%
+ }%
+ }%
+ \ifnum\count\tw@<\count@
+ \repeat
+ \expandafter\let\csname POL@arrayC\the\count@\endcsname\POL@tmp
+}%
+\def\POL@@mul@phaseIIloopbody{%
+ \advance\count@\@ne
+ \def\POL@tmp{0[0]}%
+ \count\tw@\count@
+ \advance\count\tw@-\@nameuse{POL@arrayB0} %
+ \xintloop
+ \ifnum\count\tw@<\count@
+ \advance\count\tw@\@ne
+ \edef\POL@tmp{%
+ \xintScalarAdd
+ {\POL@tmp}%
+ {\xintScalarMul
+ {\@nameuse{POL@arrayA\the\count\tw@}}%
+ {\@nameuse{POL@arrayB\the\numexpr\count@+\@ne-\count\tw@}}%
+ }%
+ }%
+ \repeat
+ \expandafter\let\csname POL@arrayC\the\count@\endcsname\POL@tmp
+}%
+\def\POL@@mul@phaseIIIloopbody{%
+ \advance\count@\@ne
+ \def\POL@tmp{0[0]}%
+ \count\tw@\count@
+ \advance\count\tw@-\@nameuse{POL@arrayB0} %
+ \xintloop
+ \advance\count\tw@\@ne
+ \edef\POL@tmp{%
+ \xintScalarAdd{\POL@tmp}%
+ {\xintScalarMul
+ {\@nameuse{POL@arrayA\the\count\tw@}}%
+ {\@nameuse{POL@arrayB\the\numexpr\count@+\@ne-\count\tw@}}%
+ }%
+ }%
+ \ifnum\@nameuse{POL@arrayA0}>\count\tw@
+ \repeat
+ \expandafter\let\csname POL@arrayC\the\count@\endcsname\POL@tmp
+}%
+
+%% POWERS (SCALAR EXPONENT...)
+\def\POL@pow #1#2{%
+ \global\POL@polfalse
+ \begingroup
+ \def\POL@result{#1}%
+ #1%
+ \expandafter
+ \endgroup
+ \expandafter\def\expandafter\POL@A\expandafter{\POL@result}%
+ \unless\ifPOL@pol
+ \edef\POL@A{\xintScalarPow{#1}{#2}}% no error check
+ \xintiiifZero{\POL@A}%
+ {\def\POL@result{-1.\empty{0/1[0]}}}%
+ {\edef\POL@result{0.\noexpand\empty{\POL@A}}}%
+ \else
+ \edef\POL@B{\numexpr\xintNum{#2}\relax}% no check on exponent >= 0
+ \ifcase\POL@B
+ \def\POL@result{0.\empty{1/1[0]}}%
+ \or
+ \let\POL@result\POL@A
+ \else
+ \POL@@pow@check
+ \fi
+ \fi
+ \global\POL@poltrue
+}%
+\def\POL@@pow@check {%
+% no problem here with leftover tokens!
+% should I have used that I-don't-care technique more elsewhere?
+ \ifnum\@ne>\POL@A
+ % polynomial is a constant, must get rid of dot and \empty
+ \edef\POL@A{\expandafter\xintScalarPow\romannumeral`^^@%
+ \expandafter\xint_gob_til_dot\POL@A{\POL@B}}%
+ \xintiiifZero{\POL@A}%
+ {\def\POL@result{-1.\empty{0/1[0]}}}%
+ {\edef\POL@result{0.\noexpand\empty{\POL@A}}}%
+ \else
+ \ifnum\@ne=\POL@A
+ % perhaps a constant times X, check constant term
+ \xintiiifZero
+ {\expandafter\xint_firstoftwo\romannumeral`^^@%
+ \expandafter\xint_gob_til_dot\POL@A}
+ {\edef\POL@result
+ {\the\POL@B.% here at least 2.
+ \noexpand\empty
+ \romannumeral\xintreplicate{\POL@B}{{0/1[0]}}%
+ {\xintScalarPow
+ {\expandafter\xint_secondoftwo\romannumeral`^^@%
+ \expandafter\xint_gob_til_dot\POL@A}%
+ {\POL@B}}}}%
+ {\POL@@pow}% not constant times X, use general recursion
+ \else
+ \POL@@pow% general recursion
+ \fi\fi
+}%
+\def\POL@@pow@recurse#1#2{%
+ \begingroup
+ #1%
+ \expandafter
+ \endgroup
+ \expandafter\def\expandafter\POL@A\expandafter{\POL@result}%
+ \edef\POL@B{\numexpr\xintNum{#2}\relax}%
+ \ifcase\POL@B
+ \POL@thisshouldneverhappen
+ \or
+ \let\POL@result\POL@A
+ \else
+ \expandafter\POL@@pow
+ \fi
+}%
+\def\POL@@pow {%
+ \let\POL@pow@exp\POL@B
+ \let\POL@B\POL@A
+ \POL@@mul
+ \let\POL@sqA\POL@result
+ \ifodd\POL@pow@exp\space
+ \expandafter\POL@@pow@odd
+ \the\numexpr(\POL@pow@exp+\@ne)/\tw@-\@ne\expandafter.%
+ \else
+ \expandafter\POL@@pow@even
+ \the\numexpr(\POL@pow@exp+\@ne)/\tw@-\@ne\expandafter.%
+ \fi
+}%
+\def\POL@@pow@even#1.{%
+ \expandafter\POL@@pow@recurse\expandafter
+ {\expandafter\def\expandafter\POL@result\expandafter{\POL@sqA}}%
+ {#1}%
+}%
+\def\POL@@pow@odd#1.{%
+ \expandafter\POL@@pow@odd@i\expandafter{\POL@A}{#1}%
+}%
+\def\POL@@pow@odd@i #1#2{%
+ \expandafter\POL@@pow@recurse\expandafter
+ {\expandafter\def\expandafter\POL@result\expandafter{\POL@sqA}}%
+ {#2}%
+ \expandafter\POL@mul\expandafter
+ {\expandafter\def\expandafter\POL@result\expandafter
+ {\POL@result}\global\POL@poltrue}%
+ {\def\POL@result{#1}\global\POL@poltrue}%
+}%
+
+%% DIVISION
+%% no check on divisor being non-zero
+\def\POL@div {\POL@get\POL@A\POL@div@b}%
+\def\POL@div@b{\POL@get\POL@B\POL@div@c}%
+\def\POL@div@c{%
+ \global\POL@poltrue
+ \expandafter\POL@split\POL@A;\POL@degA\POL@polA
+ \expandafter\POL@split\POL@B;\POL@degB\POL@polB
+ \ifnum\POL@degA<\POL@degB\space
+ \@namedef{POL@arrayQ1}{0/1[0]}%
+ \def\POL@degQ{-1}%
+ \else
+ \xintAssignArray\POL@polA\to\POL@arrayR
+ \xintAssignArray\POL@polB\to\POL@arrayB
+ \POL@@div
+ \fi
+ \count@\numexpr\POL@degQ+\@ne\relax
+ \POL@resultfromarray Q%
+}%
+\def\POL@@div{%
+ \xintAssignArray\POL@polA\to\POL@arrayR
+ \xintAssignArray\POL@polB\to\POL@arrayB
+ \edef\POL@B@leading{\csname POL@arrayB\the\numexpr\POL@degB+\@ne\endcsname}%
+ \edef\POL@degQ{\the\numexpr\POL@degA-\POL@degB}%
+ \count@\numexpr\POL@degA+\@ne\relax
+ \count\tw@\numexpr\POL@degQ+\@ne\relax
+ \xintloop
+ \POL@@div@loopbody
+ \ifnum\count\tw@>\z@
+ \repeat
+ %%\expandafter\def\csname POL@arrayR0\endcsname{1}%
+ \xintloop
+ \xintiiifZero{\csname POL@arrayR\the\count@\endcsname}%
+ {\iftrue}%
+ {\iffalse}%
+ \advance\count@\m@ne
+ \repeat
+ \edef\POL@degR{\the\numexpr\count@-\@ne}%
+}%
+\def\POL@@div@loopbody{%
+ \edef\POL@@div@ratio{%
+ \xintScalarDiv{\csname POL@arrayR\the\count@\endcsname}%
+ {\POL@B@leading}}%
+ \expandafter\let\csname POL@arrayQ\the\count\tw@\endcsname
+ \POL@@div@ratio
+ \advance\count@\m@ne
+ \advance\count\tw@\m@ne
+ \count4 \count@
+ \count6 \POL@degB\space
+ \xintloop
+ \ifnum\count6>\z@
+ \expandafter\edef\csname POL@arrayR\the\count4\endcsname
+ {\xintScalarSub
+ {\csname POL@arrayR\the\count4\endcsname}%
+ {\xintScalarMul
+ {\POL@@div@ratio}%
+ {\csname POL@arrayB\the\count6\endcsname}}}%
+ \advance\count4 \m@ne
+ \advance\count6 \m@ne
+ \repeat
+}%
+
+%% MINUS SIGN AS UNARY OPERATOR
+\def\POL@opp #1{%
+ \global\POL@polfalse
+ \begingroup
+ \def\POL@result{#1}%
+ #1%
+ \expandafter
+ \endgroup
+ \expandafter\def\expandafter\POL@A\expandafter{\POL@result}%
+ \unless\ifPOL@pol
+ \edef\POL@A{\xintScalarOpp{#1}}%
+ \xintiiifZero{\POL@A}%
+ {\def\POL@result{-1.\empty{0/1[0]}}}%
+ {\edef\POL@result{0.\noexpand\empty{\POL@A}}}%
+ \else
+ \edef\POL@B{0.\noexpand\empty{-1/1[0]}}%
+ \POL@@mul
+ \fi
+ \global\POL@poltrue
+}%
+
+
+%% EXPANDABLE MACROS
+\def\POL@eval@fork#1\At#2#3\krof{#2}%
+\newcommand\PolEval[3]{\romannumeral`^^@\POL@eval@fork
+ #2\PolEvalAt
+ \At\PolEvalAtExpr\krof {#1}{#3}%
+}%
+\newcommand\PolEvalAt[2]
+ {\xintpraw{\csname XINT_expr_userfunc_#1\endcsname{#2}}}%
+\newcommand\POL@eval[2]
+ {\csname XINT_expr_userfunc_#1\endcsname{#2}}%
+\newcommand\PolEvalAtExpr[2]{\xinttheexpr #1(#2)\relax}%
+%
+\newcommand\PolEvalReduced[3]{\romannumeral`^^@\POL@eval@fork
+ #2\PolEvalReducedAt
+ \At\PolEvalReducedAtExpr\krof {#1}{#3}%
+}%
+\newcommand\PolEvalReducedAt[2]{%
+ \xintpraw % in order not to print denominator if the latter equals 1
+ {\xintIrr{\csname XINT_expr_userfunc_#1\endcsname{#2}}[0]}%
+}%
+\newcommand\PolEvalReducedAtExpr[2]{%
+ \xintpraw
+ {\xintIrr{\romannumeral`^^@\xintthebareeval#1(#2)\relax}[0]}%
+}%
+%
+\newcommand\PolFloatEval[3]{\romannumeral`^^@\POL@eval@fork
+ #2\PolFloatEvalAt
+ \At\PolFloatEvalAtExpr\krof {#1}{#3}%
+}%
+\newcommand\PolFloatEvalAt[2]
+ {\xintpfloat{\csname XINT_flexpr_userfunc_#1\endcsname{#2}}}%
+\newcommand\PolFloatEvalAtExpr[2]{\xintthefloatexpr #1(#2)\relax}%
+
+
+\newcommand\PolSturmIntervalIndex[3]{\the\numexpr\POL@eval@fork
+ #2\PolSturmIntervalIndexAt
+ \At\PolSturmIntervalIndexAtExpr\krof {#1}{#3}%
+}%
+\newcommand\PolSturmIntervalIndexAtExpr[2]
+ {\PolSturmIntervalIndexAt{#1}{\xinttheexpr#2\relax}}%
+\newcommand\PolSturmIntervalIndexAt[2]
+ {\expandafter\POL@sturm@index@at\romannumeral`^^@#2!{#1}\xint_bye\relax}%
+\def\POL@sturm@index@at#1!#2%
+{%
+ \expandafter\POL@sturm@index@at@iloop
+ \romannumeral`^^@\PolSturmNbOfIsolatedZeros{#2}!{#2}{#1}%
+}%
+% implementation is sub-optimal as it should use some kind of binary tree
+% search rather than comparing to the intervals from right to left as here
+\def\POL@sturm@index@at@iloop #1!%
+{%
+ \ifnum #1=\z@ 0\expandafter\xint_bye\fi
+ \POL@sturm@index@at@iloop@a #1!%
+}%
+\def\POL@sturm@index@at@iloop@a #1!#2#3%
+{% #1 = index, #2 = sturmname, #3 value
+ \PolSturmIfZeroExactlyKnown{#2}{#1}
+ {\xintifCmp{#3}{\POL@xintexprGetVar{#2L_#1}}%
+ {}%
+ {#1\xint_bye}%
+ {0\xint_bye}%
+ }%
+ {\xintifGt{#3}{\POL@xintexprGetVar{#2L_#1}}%
+ {\xintifLt{#3}{\POL@xintexprGetVar{#2R_#1}}%
+ {#1\xint_bye}%
+ {0\xint_bye}%
+ }%
+ {}%
+ }%
+ % catcode of ! is 11 in polexpr.sty
+ \expandafter\POL@sturm@index@at@iloop\the\numexpr#1-\@ne !{#2}{#3}%
+}%
+
+
+\def\POL@leq@fork#1\LessThanOrEqualTo#2#3\krof{#2}%
+\newcommand\PolSturmNbOfRootsOf[3]{\romannumeral`^^@\POL@leq@fork
+ #2\PolNbOfRootsLessThanOrEqualTo
+ \LessThanOrEqualTo\PolNbOfRootsLessThanOrEqualToExpr\krof {#1}{#3}%
+}%
+\newcommand\PolNbOfRootsLessThanOrEqualToExpr[2]
+ {\PolNbOfRootsLessThanOrEqualTo{#1}{\xinttheexpr#2\relax}}%
+\newcommand\PolNbOfRootsLessThanOrEqualTo[1]{%
+ \ifnum\PolSturmNbOfIsolatedZeros{#1}=\z@
+ \expandafter\xint_firstofthree\expandafter0%
+ \else
+ \expandafter\PolNbOfRootsLessThanOrEqualTo@%
+ \fi {#1}%
+}%
+\def\PolNbOfRootsLessThanOrEqualTo@ #1#2%
+{%
+ \expandafter\POL@nbofrootsleq@prep\romannumeral`^^@#2!{#1}%
+}%
+\def\POL@nbofrootsleq@prep#1!#2%
+{%
+ \expandafter\POL@nbofrootsleq@iloop\expandafter 1\expandafter !%
+ \romannumeral0\xintsgn{\POL@eval{#2_0}{#1}}!%
+ #1!{#2}%
+}%
+\def\POL@nbofrootsleq@iloop#1!#2!#3!#4%
+{% #1 = index, #2 = sign of evaluation at value, #3 = value, #4 = sturmname
+ \xintifCmp{#3}{\POL@xintexprGetVar{#4L_#1}}%
+ {\POL@nbofrootsleq@return #1-\@ne !}%
+ {\POL@nbofrootsleq@return
+ \PolSturmIfZeroExactlyKnown{#4}{#1}{#1}{#1-\@ne}!%
+ }%
+ % in third branch we are sure that if root is exactly known
+ % the test \xintifLt will be negative
+ {\xintifLt{#3}{\POL@xintexprGetVar{#4R_#1}}%
+ {\POL@nbofrootsleq@return
+ #1\ifnum#2=\xintSgn{\POL@eval{#4_0}{\POL@xintexprGetVar{#4L_#1}}}
+ -\@ne\fi !%
+ }%
+ {\ifnum#1=\PolSturmNbOfIsolatedZeros{#4}
+ \expandafter\POL@nbofrootsleq@rightmost
+ \fi \expandafter\POL@nbofrootsleq@iloop \the\numexpr\@ne+%
+ }%
+ }%
+ #1!#2!#3!{#4}%
+}%
+\def\POL@nbofrootsleq@return #1!#2!#3!#4!#5{\the\numexpr #1\relax}%
+\def\POL@nbofrootsleq@rightmost\expandafter\POL@nbofrootsleq@iloop
+ \the\numexpr\@ne+#1!#2!#3!#4{#1}%
+
+
+\newcommand\PolSturmNbWithMultOfRootsOf[3]
+{\the\numexpr0\POL@leq@fork
+ #2\PolNbWithMultOfRootsLessThanOrEqualTo
+ \LessThanOrEqualTo\PolNbWithMultOfRootsLessThanOrEqualToExpr\krof {#1}{#3}%
+}%
+\newcommand\PolNbWithMultOfRootsLessThanOrEqualToExpr[2]
+ {\PolNbWithMultOfRootsLessThanOrEqualTo{#1}{\xinttheexpr#2\relax}}%
+\newcommand\PolNbWithMultOfRootsLessThanOrEqualTo[1]{%
+ \ifnum\PolSturmNbOfIsolatedZeros{#1}=\z@
+ \expandafter\POL@nbwmofroots@noroots
+ \else
+ \expandafter\PolNbWithMultOfRootsLessThanOrEqualTo@%
+ \fi {#1}%
+}%
+\def\POL@nbwmofroots@noroots#1#2{\relax}%
+\def\PolNbWithMultOfRootsLessThanOrEqualTo@ #1#2%
+{%
+ \expandafter\POL@nbwmofrootsleq@prep\romannumeral`^^@#2!{#1}%
+}%
+\def\POL@nbwmofrootsleq@prep#1!#2%
+{%
+ \expandafter\POL@nbwmofrootsleq@iloop\expandafter 1\expandafter !%
+ \romannumeral0\xintsgn{\POL@eval{#2_0}{#1}}!%
+ #1!{#2}%
+}%
+\def\POL@nbwmofrootsleq@iloop#1!#2!#3!#4%
+{% #1 = index, #2 = sign of evaluation at value, #3 = value, #4 = sturmname
+ \xintifCmp{#3}{\POL@xintexprGetVar{#4L_#1}}%
+ {\POL@nbwmofrootsleq@return !}%
+ {\POL@nbwmofrootsleq@return
+ \PolSturmIfZeroExactlyKnown{#4}{#1}%
+ {+\PolSturmIsolatedZeroMultiplicity{#4}{#1}}{}!%
+ }%
+ % in third branch we are sure that if root is exactly known
+ % the test \xintifLt will be negative
+ {\xintifLt{#3}{\POL@xintexprGetVar{#4R_#1}}%
+ {\POL@nbwmofrootsleq@return
+ \unless
+ \ifnum#2=\xintSgn{\POL@eval{#4_0}{\POL@xintexprGetVar{#4L_#1}}}
+ +\PolSturmIsolatedZeroMultiplicity{#4}{#1}\fi !%
+ }%
+ {+\PolSturmIsolatedZeroMultiplicity{#4}{#1}%
+ \ifnum#1=\PolSturmNbOfIsolatedZeros{#4}
+ \expandafter\POL@nbwmofrootsleq@return\expandafter !%
+ \fi
+ \expandafter\POL@nbwmofrootsleq@iloop \the\numexpr\@ne+%
+ }%
+ }%
+ #1!#2!#3!{#4}%
+}%
+\def\POL@nbwmofrootsleq@return #1!#2!#3!#4!#5{#1\relax}%
+
+
+\newcommand\PolLeadingCoeff[1]{%
+ \romannumeral`^^@\expandafter\expandafter\expandafter\xintlastitem
+ \expandafter\expandafter\expandafter
+ {\csname POLuserpol@#1\endcsname}%
+}%
+%
+\newcommand\PolNthCoeff[2]{\romannumeral`^^@%
+ \expandafter\POL@nthcoeff
+ \romannumeral0\xintnthelt{\ifnum\numexpr#2<\z@#2\else(#2)+1\fi}%
+ {\expandafter\expandafter\expandafter
+ \xint_gob_til_dot\csname POLuserpol@#1\endcsname}@%
+}%
+\def\POL@nthcoeff#1@{\if @#1@\expandafter\xint_firstoftwo
+ \else\expandafter\xint_secondoftwo\fi
+ {0/1[0]}{#1}}%
+%
+% returns -1 for zero polynomial for context of numerical expression
+% should it return -\infty?
+\newcommand\PolDegree[1]{\romannumeral`^^@\expandafter\expandafter\expandafter
+ \POL@degree\csname POLuserpol@#1\endcsname;}%
+\def\POL@degree #1.#2;{#1}%
+%
+\newcommand\PolToList[1]{\romannumeral`^^@\expandafter\expandafter\expandafter
+ \xint_gob_til_dot\csname POLuserpol@#1\endcsname}%
+%
+\newcommand\PolToCSV[1]{\romannumeral0\xintlistwithsep{, }{\PolToList{#1}}}%
+
+
+\newcommand\PolToExprCmd[1]{\xintPRaw{\xintRawWithZeros{#1}}}%
+\newcommand\PolToFloatExprCmd[1]{\xintFloat{#1}}%
+\let\PolToExprTermPrefix\PolTypesetCmdPrefix
+\newcommand\PolToExprOneTermStyleA[2]{%
+ \ifnum#2=\z@
+ \PolToExprCmd{#1}%
+ \else
+ \xintifOne{\xintiiAbs{#1}}
+ {\xintiiifSgn{#1}{-}{}{}}% + from \PolToExprTermPrefix
+ {\PolToExprCmd{#1}\PolToExprTimes}%
+ \fi
+ \ifcase\xintiiAbs{#2} %<-- space here mandatory
+ \or\PolToExprVar
+ \else\PolToExprVar^\xintiiAbs{#2}%
+ \fi
+}%
+\let\PolToExprOneTerm\PolToExprOneTermStyleA
+\newcommand\PolToExprOneTermStyleB[2]{%
+ \ifnum#2=\z@
+ \xintNumerator{#1}%
+ \else
+ \xintifOne{\xintiiAbs{\xintNumerator{#1}}}
+ {\xintiiifSgn{#1}{-}{}{}}% + from \PolToExprTermPrefix
+ {\xintNumerator{#1}\PolToExprTimes}%
+ \fi
+ \ifcase\xintiiAbs{#2} %<-- space here mandatory
+ \or\PolToExprVar
+ \else\PolToExprVar^\xintiiAbs{#2}%
+ \fi
+ \xintiiifOne{\xintDenominator{#1}}{}{/\xintDenominator{#1}}%
+}%
+\newcommand\PolToFloatExprOneTerm[2]{%
+ \ifnum#2=\z@
+ \PolToFloatExprCmd{#1}%
+ \else
+ \PolToFloatExprCmd{#1}\PolToExprTimes
+ \fi
+ \ifcase\xintiiAbs{#2} %<-- space here mandatory
+ \or\PolToExprVar
+ \else\PolToExprVar^\xintiiAbs{#2}%
+ \fi
+}%
+\newcommand\PolToExprTimes{*}%
+\newcommand\PolToExprVar{x}%
+\newcommand\PolToExpr[1]{%
+ \if*\noexpand#1\expandafter\xint_firstoftwo\else
+ \expandafter\xint_secondoftwo\fi
+ \PolToExprAscending\PolToExprDescending{#1}}%
+\newcommand\PolToFloatExpr[1]{%
+ \if*\noexpand#1\expandafter\xint_firstoftwo\else
+ \expandafter\xint_secondoftwo\fi
+ \PolToFloatExprAscending\PolToFloatExprDescending{#1}}%
+\newcommand\PolToExprAscending[2]{%
+ \expandafter\POL@toexpr\csname POLuserpol@#2\endcsname
+ \PolToExprOneTerm\POL@toexprA}%
+\newcommand\PolToFloatExprAscending[2]{%
+ \expandafter\POL@toexpr\csname POLuserpol@#2\endcsname
+ \PolToFloatExprOneTerm\POL@toexprA}%
+\newcommand\PolToExprDescending[1]{%
+ \expandafter\POL@toexpr\csname POLuserpol@#1\endcsname
+ \PolToExprOneTerm\POL@toexprD}%
+\newcommand\PolToFloatExprDescending[1]{%
+ \expandafter\POL@toexpr\csname POLuserpol@#1\endcsname
+ \PolToFloatExprOneTerm\POL@toexprD}%
+%
+\def\POL@toexpr#1#2#3{\expandafter\POL@toexpr@
+ \expandafter#3\expandafter#2#1\relax}%
+\def\POL@toexpr@#1#2#3.{%
+ \ifnum#3<\z@
+ #2{0/1[0]}{0}\expandafter\xint_gobble_v
+ \else
+ \expandafter#1%
+ \fi {#3}#2}%
+%
+\def\POL@toexprA #1#2\empty#3{%
+ \ifpoltoexprall\expandafter\POL@toexprall@b
+ \else\expandafter\POL@toexpr@b
+ \fi {#3}#2{0}1.%
+}%
+\def\POL@toexprD #1#2#3\relax{% #3 has \empty to prevent brace removal
+ \expandafter\POL@toexprD@a\expandafter#2%
+ \the\numexpr #1\expandafter.\romannumeral0\xintrevwithbraces{#3}\relax
+}%
+\def\POL@toexprD@a #1#2.#3{%
+ \ifpoltoexprall\expandafter\POL@toexprall@b
+ \else\expandafter\POL@toexpr@b
+ \fi{#3}#1{-#2}\the\numexpr\@ne+-#2.%
+}%
+\def\POL@toexpr@b #1#2#3{%
+ \xintiiifZero{#1}%
+ {\expandafter\POL@toexpr@loop\expandafter\POL@toexpr@b}%
+ {#2{#1}{#3}%
+ \expandafter\POL@toexpr@loop\expandafter\POL@toexpr@c}%
+ \expandafter#2%
+}%
+\def\POL@toexpr@c #1#2#3{%
+ \xintiiifZero{#1}%
+ {}%
+ {\PolToExprTermPrefix{#1}#2{#1}{#3}}%
+ \expandafter\POL@toexpr@loop\expandafter\POL@toexpr@c
+ \expandafter#2%
+}%
+\def\POL@toexprall@b #1#2#3{%
+ #2{#1}{#3}%
+ \expandafter\POL@toexpr@loop\expandafter\POL@toexprall@c
+ \expandafter#2%
+}%
+\def\POL@toexprall@c #1#2#3{%
+ \PolToExprTermPrefix{#1}#2{#1}{#3}%
+ \expandafter\POL@toexpr@loop\expandafter\POL@toexprall@c
+ \expandafter#2%
+}%
+\def\POL@toexpr@loop#1#2#3.#4{%
+ \if\relax#4\expandafter\xint_gob_til_dot\fi
+ #1{#4}#2{#3}\the\numexpr\@ne+#3.%
+}%
+
+
+\POL@restorecatcodes
+\endinput
diff --git a/macros/latex/contrib/polexpr/polexpr.txt b/macros/latex/contrib/polexpr/polexpr.txt
new file mode 100644
index 0000000000..46ea7e32fa
--- /dev/null
+++ b/macros/latex/contrib/polexpr/polexpr.txt
@@ -0,0 +1,2593 @@
+.. comment: -*- fill-column: 72; mode: rst; -*-
+
+===============================
+ Package polexpr documentation
+===============================
+
+0.7.4 (2019/02/12)
+==================
+
+.. contents::
+
+Basic syntax
+------------
+
+The syntax is::
+
+ \poldef polname(x):= expression in variable x;
+
+where:
+
+- in place of ``x`` an arbitrary *dummy variable* is authorized,
+ i.e. per default any of ``[a-z|A-Z]`` (more letters can be declared
+ under Unicode engines.)
+
+- ``polname`` consists of letters, digits, and the ``_`` and
+ ``'`` characters. It must start with a letter.
+
+.. attention::
+
+ The ``'`` is authorized since ``0.5.1``. As a result some constructs
+ recognized by the ``\xintexpr`` parser, such as ``var1 'and' var2``
+ will get misinterpreted and cause errors. However these constructs
+ are unlikely to be frequently needed in polynomial expressions, and
+ the ``\xintexpr`` syntax offers alternatives, so it was deemed a
+ small evil. Of course the ``\xintexpr`` parser is modified only
+ temporarily during execution of ``\poldef``.
+
+One can also issue::
+
+ \PolDef{polname}{expression in variable x}
+
+which admits an optional first argument to modify the variable letter
+from its default ``x``.
+
+``\poldef f(x):= 1-x+x^2;``
+ defines polynomial ``f``. Polynomial names must start with a
+ letter and may contain letters, digits, underscores and the right
+ tick character. The
+ variable must be a single letter. The colon character is optional.
+ The semi-colon at end of expression is mandatory.
+
+``\PolDef{f}{1-x+x^2}``
+ does the same as ``\poldef f(x):= 1-x+x^2;`` To use another letter
+ than ``x`` in the expression, one must pass it as an extra optional
+ argument to ``\PolDef``. Useful if the semi-colon has been assigned
+ some non-standard catcode by some package.
+
+``\PolLet{g}={f}``
+ saves a copy of ``f`` under name ``g``. Also usable without ``=``.
+
+``\poldef f(z):= f(z)^2;``
+ redefines ``f`` in terms of itself.
+
+``\poldef f(T):= f(f(T));``
+ again redefines ``f`` in terms of its (new) self.
+
+``\poldef k(z):= f(z)-g(g(z)^2)^2;``
+ should now define the zero polynomial... Let's check:
+ ``\[ k(z) = \PolTypeset[z]{k} \]``
+
+``\PolDiff{f}{f'}``
+ sets ``f'`` to the derivative of ``f``. The name doesn't have to be
+ ``f'`` (in fact the ``'`` is licit only since ``0.5.1``).
+
+.. important::
+
+ This is not done automatically. If some new definition needs to use
+ the derivative of some available polynomial, that derivative
+ polynomial must have been defined via ``\PolDiff``: something like
+ ``T'(x)^2`` will not work without a prior ``\PolDiff{T}{T'}``.
+
+``\PolDiff{f'}{f''}``
+ obtains second derivative.
+
+``\PolDiff[3]{f}{f'''}``
+ computes the third derivative.
+
+::
+
+ $f(z) = \PolTypeset[z]{f} $\newline
+ $f'(z) = \PolTypeset[z]{f'} $\newline
+ $f''(z) = \PolTypeset[z]{f''} $\newline
+ $f'''(z)= \PolTypeset[z]{f'''} $\par
+
+.. important::
+
+ The package does not currently know rational functions: ``/`` in
+ a parsed polynomial expression does the Euclidean quotient::
+
+ (1-x^2)/(1-x)
+
+ does give ``1+x`` but ::
+
+ (1/(1-x))*(1-x^2)
+
+ evaluates to zero. This will work as expected::
+
+ \poldef k(x):= (x-1)(x-2)(x-3)(x-4)/(x^2-5x+4);
+
+.. _warningtacit:
+
+.. attention::
+
+ ``1/2 x^2`` skips the space and is treated like ``1/(2*x^2)`` because
+ of the tacit multiplication rules of \xintexpr. But this means it
+ gives zero! Thus one must use ``(1/2)x^2`` or ``1/2*x^2`` or
+ ``(1/2)*x^2`` for disambiguation: ``x - 1/2*x^2 + 1/3*x^3...``. It is
+ even simpler to move the denominator to the right: ``x - x^2/2 +
+ x^3/3 - ...``.
+
+ It is worth noting that ``1/2(x-1)(x-2)`` suffers the same issue:
+ xint_ tacit multiplication always "ties more", hence this gets
+ interpreted as ``1/(2*(x-1)*(x-2))`` which gives zero by polynomial
+ division. Thus, use one of ``(1/2)(x-1)(x-2)``, ``1/2*(x-1)(x-2)`` or
+ ``(x-1)(x-2)/2``.
+
+After::
+
+ \poldef f_1(x):= 25(x-1)(x^2-2)(x-3)(x-4)(x-5);%
+ \poldef f_2(x):= 37(x-1)(x^2-2)(x-6)(x-7)(x-8);%
+
+the macro call ``\PolGCD{f_1}{f_2}{k}`` sets ``k`` to the (unitary) GCD of
+``f_1`` and ``f_2`` (hence to the expansion of ``(x-1)(x^2-2)``.)
+
+``\PolToExpr{k}``
+ will (expandably) give in this case ``x^3-x^2-2*x+2``. This is
+ useful for console or file output (the syntax is Maple- and
+ PSTricks-compatible; the letter used in output can be
+ (non-expandably) changed via a redefinition of `\\PolToExprVar`_.)
+
+``\PolToExpr*{k}``
+ gives ascending powers: ``2-2*x-x^2+x^3``.
+
+Examples of localization of roots
+---------------------------------
+
+- To make printed decimal numbers more enjoyable than via
+ ``\xintSignedFrac``::
+
+ \renewcommand\PolTypesetOne[1]{\PolDecToString{\xintREZ{#1}}}%
+
+ ``\PolDecToString`` will use decimal notation to incorporate the power
+ of ten part; and the ``\xintREZ`` will have the effect to suppress
+ trailing zeros if present in raw numerator (if those digits end up
+ after decimal mark.) Notice that the above are expandable macros and
+ that one can also do::
+
+ \renewcommand\PolToExprCmd[1]{\PolDecToString{\xintREZ{#1}}}%
+
+ to modify output of `\\PolToExpr{polname}`_.
+
+- For extra info in log file use ``\xintverbosetrue``.
+
+- Only for some of these examples is the output included here.
+
+
+A typical example
+~~~~~~~~~~~~~~~~~
+
+In this example the polynomial is square-free.
+
+::
+
+ \poldef f(x) := x^7 - x^6 - 2x + 1;
+
+ \PolToSturm{f}{f}
+ \PolSturmIsolateZeros{f}
+ The \PolTypeset{f} polynomial has \PolSturmNbOfIsolatedZeros{f} distinct real
+ roots which are located in the following intervals:
+ \PolPrintIntervals{f}
+ Here is the second root with ten more decimal digits:
+ \PolRefineInterval[10]{f}{2}
+ \[\PolSturmIsolatedZeroLeft{f}{2}<Z_2<\PolSturmIsolatedZeroRight{f}{2}\]
+ And here is the first root with twenty digits after decimal mark:
+ \PolEnsureIntervalLength{f}{1}{-20}
+ \[\PolSturmIsolatedZeroLeft{f}{1}<Z_1<\PolSturmIsolatedZeroRight{f}{1}\]
+ The first element of the Sturm chain has degree $\PolDegree{f_0}$. As
+ this is the original degreee $\PolDegree{f}$ we know that $f$ is square free.
+ Its derivative is up to a constant \PolTypeset{f_1} (in this example
+ it is identical with it).
+ \PolToSturm{f_1}{f_1}\PolSturmIsolateZeros{f_1}%
+ The derivative has \PolSturmNbOfIsolatedZeros{f_1} distinct real
+ roots:
+ \PolPrintIntervals[W]{f_1}
+ \PolEnsureIntervalLengths{f_1}{-10}%
+ Here they are with ten digits after decimal mark:
+ \PolPrintIntervals[W]{f_1}
+ \PolDiff{f_1}{f''}
+ \PolToSturm{f''}{f''}
+ \PolSturmIsolateZeros{f''}
+ The second derivative is \PolTypeset{f''}.
+ It has \PolSturmNbOfIsolatedZeros{f''} distinct real
+ roots:
+ \PolPrintIntervals[X]{f''}
+ Here is the positive one with 20 digits after decimal mark:
+ \PolEnsureIntervalLength{f''}{2}{-20}%
+ \[X_2 = \PolSturmIsolatedZeroLeft{f''}{2}\dots\]
+ The more mathematically advanced among our dear readers will be able
+ to give the exact value for $X_2$!
+
+A degree four polynomial with nearby roots
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Notice that this example is a bit outdated as ``0.7`` release has
+added ``\PolSturmIsolateZeros**{sturmname}`` which would find exactly
+the roots. The steps here retain their interest when one is interested
+in finding isolating intervals for example to prepare some demonstration
+of dichotomy method.
+
+
+::
+
+ \PolDef{Q}{(x-1.050001)(x-1.105001)(x-1.110501)(x-1.111051)}
+ \PolTypeset{Q}
+ \PolToSturm{Q}{Q} % it is allowed to use same prefix for Sturm chain
+ \PolSturmIsolateZeros{Q}
+ \PolPrintIntervals{Q}
+ % reports 1.0 < Z_1 < 1.1, 1.10 < Z_2 < 1.11, 1.110 < Z_3 < 1.111, and 1.111 < Z_4 < 1.112
+ % but the above bounds do not allow minimizing separation between roots
+ % so we refine:
+ \PolRefineInterval*{Q}{1}
+ \PolRefineInterval*{Q}{2}
+ \PolRefineInterval*{Q}{3}
+ \PolRefineInterval*{Q}{4}
+ \PolPrintIntervals{Q}
+ % reports 1.05 < Z_1 < 1.06, 1.105 < Z_2 < 1.106, 1.1105 < Z_3 < 1.1106,
+ % and 1.11105 < Z_4 < 1.11106.
+ \PolEnsureIntervalLengths{Q}{-6}
+ \PolPrintIntervals{Q}
+ % of course finds here all roots exactly
+
+
+The degree nine polynomial with 0.99, 0.999, 0.9999 as triple roots
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ % define a user command (xinttools is loaded automatically by polexpr)
+ \newcommand\showmultiplicities[1]{% #1 = "sturmname"
+ \xintFor* ##1 in {\xintSeq{1}{\PolSturmNbOfIsolatedZeros{#1}}}\do{%
+ The multiplicity is \PolSturmIsolatedZeroMultiplicity{#1}{##1}
+ \PolSturmIfZeroExactlyKnown{#1}{##1}%
+ {at the root $x=\PolSturmIsolatedZeroLeft{#1}{##1}$}
+ {for the root such that
+ $\PolSturmIsolatedZeroLeft{#1}{##1}<x<\PolSturmIsolatedZeroRight{#1}{##1}$}
+ \par
+ }}%
+ \PolDef{f}{(x-0.99)^3(x-0.999)^3(x-0.9999)^3}
+ \renewcommand\PolTypesetOne[1]{\PolDecToString{\xintREZ{#1}}}
+ \PolTypeset{f}\par
+ \PolToSturm{f}{f}% it is allowed to use "polname" as "sturmname" too
+ \PolSturmIsolateZerosAndGetMultiplicities{f}% use the "sturmname" here
+ % or \PolSturmIsolateZeros*{f} which is exactly the same, but shorter..
+
+ \showmultiplicities{f}
+
+In this example, the output will look like this (but using math mode)::
+
+ x^9 - 8.9667x^8 + 35.73400293x^7 - 83.070418400109x^6 + 124.143648875193123x^5
+ - 123.683070924326075877x^4 + 82.149260397553075617891x^3
+ - 35.07602992699900159127007x^2 + 8.7364078733314648368671733x
+ - 0.967100824643585986488103299
+
+ The multiplicity is 3 at the root x = 0.99
+ The multiplicity is 3 at the root x = 0.999
+ The multiplicity is 3 at the root x = 0.9999
+
+On first pass, these rational roots were found (due to their relative
+magnitudes, using ``\PolSturmIsolateZeros**`` was not needed here). But
+multiplicity computation works also with (decimal) roots not yet
+identified or with non-decimal or irrational roots.
+
+It is fun to modify only a tiny bit the polynomial and see if polexpr
+survives::
+
+ \PolDef{g}{f(x)+1e-27}
+ \PolTypeset{g}\par
+ \PolToSturm{g}{g}
+ \PolSturmIsolateZeros*{g}
+
+ \showmultiplicities{g}
+
+This produces::
+
+ x^9 - 8.9667x^8 + 35.73400293x^7 - 83.070418400109x^6 + 124.143648875193123x^5
+ - 123.683070924326075877x^4 + 82.149260397553075617891x^3
+ - 35.07602992699900159127007x^2 + 8.7364078733314648368671733x
+ - 0.967100824643585986488103298
+
+ The multiplicity is 1 for the root such that 0.98 < x < 0.99
+ The multiplicity is 1 for the root such that 0.9991 < x < 0.9992
+ The multiplicity is 1 for the root such that 0.9997 < x < 0.9998
+
+Which means that the multiplicity-3 roots each became a real and a pair of
+complex ones. Let's see them better::
+
+ \PolEnsureIntervalLengths{g}{-10}
+
+ \showmultiplicities{g}
+
+which produces::
+
+ The multiplicity is 1 for the root such that 0.9899888032 < x < 0.9899888033
+ The multiplicity is 1 for the root such that 0.9991447980 < x < 0.9991447981
+ The multiplicity is 1 for the root such that 0.9997663986 < x < 0.9997663987
+
+A degree five polynomial with three rational roots
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ \poldef Q(x) := 1581755751184441 x^5
+ -14907697165025339 x^4
+ +48415668972339336 x^3
+ -63952057791306264 x^2
+ +46833913221154895 x
+ -49044360626280925;
+
+ \PolToSturm{Q}{Q}
+ %\begin{flushleft}
+ \renewcommand\PolTypesetCmdPrefix[1]{\allowbreak\xintiiifSgn{#1}{}{+}{+}}%
+ $Q_0(x) = \PolTypeset{Q_0}$
+ %\end{flushleft}
+ \PolSturmIsolateZeros**{Q}
+ \PolPrintIntervals{Q}
+
+ $Q_{norr}(x) = \PolTypeset{Q_norr}$
+
+Here, all real roots are rational::
+
+ Z_1 = 833719/265381
+ Z_2 = 165707065/52746197
+ Z_3 = 355/113
+
+ Q_norr(x) = x^2 + 1
+
+And let's get their decimal expansion too::
+
+ % print decimal expansion of the found roots
+ \renewcommand\PolPrintIntervalsPrintExactZero
+ {\xintTrunc{20}{\PolPrintIntervalsTheLeftEndPoint}\dots}
+ \PolPrintIntervals{Q}
+
+ Z_1 = 3.14159265358107777120...
+ Z_2 = 3.14159265358979340254...
+ Z_3 = 3.14159292035398230088...
+
+
+A Mignotte type polynomial
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ \PolDef{P}{x^10 - (10x-1)^2}%
+ \PolTypeset{P} % prints it in expanded form
+ \PolToSturm{P}{P} % we can use same prefix for Sturm chain
+ \PolSturmIsolateZeros{P} % finds 4 real roots
+ This polynomial has \PolSturmNbOfIsolatedZeros{P} distinct real roots:
+ \PolPrintIntervals{P}%
+ % reports -2 < Z_1 < -1, 0.09 < Z_2 < 0.10, 0.1 < Z_3 < 0.2, 1 < Z_4 < 2
+ Let us refine the second and third intervals to separate the corresponding
+ roots:
+ \PolRefineInterval*{P}{2}% will refine to 0.0999990 < Z_2 < 0.0999991
+ \PolRefineInterval*{P}{3}% will refine to 0.100001 < Z_3 < 0.100002
+ \PolPrintIntervals{P}%
+ Let us now get to know all roots with 10 digits after decimal mark:
+ \PolEnsureIntervalLengths{P}{-10}%
+ \PolPrintIntervals{P}% now all roots are known 10 decimal digits after mark
+ Finally, we display 20 digits of the second root:
+ \PolEnsureIntervalLength{P}{2}{-20}% makes Z_2 known with 20 digits after mark
+ \[\PolSturmIsolatedZeroLeft{P}{2}<Z_2<\PolSturmIsolatedZeroRight{P}{2}\]
+
+The last line produces::
+
+ 0.09999900004999650028 < Z_2 < 0.09999900004999650029
+
+
+The Wilkinson polynomial
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+See `Wilkinson polynomial`_.
+
+::
+
+ \documentclass{article}
+ \usepackage{polexpr}
+ \begin{document}
+ %\xintverbosetrue % for the curious...
+
+ \poldef f(x) := mul((x - i), i = 1..20);
+
+ \renewcommand\PolTypesetCmdPrefix[1]{\allowbreak\xintiiifSgn{#1}{}{+}{+}}%
+ \renewcommand\PolTypesetOne[1]{\xintDecToString{#1}}%
+
+ \noindent\PolTypeset{f}
+
+ \PolToSturm{f}{f}
+ \PolSturmIsolateZeros{f}
+ \PolPrintIntervals{f}
+
+ \clearpage
+
+ \poldef g(x) := f(x) - 2**{-23} x**19;
+
+ % be patient!
+ \PolToSturm{g}{g}
+ \noindent\PolTypeset{g_0}% integer coefficient primitive polynomial
+
+ \PolSturmIsolateZeros{g}
+ \PolEnsureIntervalLengths{g}{-10}
+
+ \renewcommand\PolPrintIntervalsPrintMultiplicity{}
+ \PolPrintIntervals*{g}
+
+ \end{document}
+
+
+The first polynomial::
+
+ f(x) = x**20
+ - 210 x**19
+ + 20615 x**18
+ - 1256850 x**17
+ + 53327946 x**16
+ - 1672280820 x**15
+ + 40171771630 x**14
+ - 756111184500 x**13
+ + 11310276995381 x**12
+ - 135585182899530 x**11
+ + 1307535010540395 x**10
+ - 10142299865511450 x**9
+ + 63030812099294896 x**8
+ - 311333643161390640 x**7
+ + 1206647803780373360 x**6
+ - 3599979517947607200 x**5
+ + 8037811822645051776 x**4
+ - 12870931245150988800 x**3
+ + 13803759753640704000 x**2
+ - 8752948036761600000 x
+ + 2432902008176640000
+
+is handled fast enough (a few seconds), but the modified one ``f(x) -
+2**-23 x**19`` takes about 20x longer (the Sturm chain polynomials
+have integer coefficients with up to 321 digits, whereas (surprisingly
+perhaps) those of the Sturm chain polynomials derived from ``f`` never
+have more than 21 digits ...).
+
+Once the Sturm chain is computed and the zeros isolated, obtaining their
+decimal digits is relatively faster. Here is for the ten real roots of
+``f(x) - 2**-23 x**19`` as computed by the code above::
+
+ Z_1 = 0.9999999999...
+ Z_2 = 2.0000000000...
+ Z_3 = 2.9999999999...
+ Z_4 = 4.0000000002...
+ Z_5 = 4.9999999275...
+ Z_6 = 6.0000069439...
+ Z_7 = 6.9996972339...
+ Z_8 = 8.0072676034...
+ Z_9 = 8.9172502485...
+ Z_10 = 20.8469081014...
+
+The second Wilkinson polynomial
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ \documentclass{article}
+ \usepackage{polexpr}
+ \begin{document}
+ \poldef f(x) := mul(x - 2^-i, i = 1..20);
+
+ %\PolTypeset{f}
+
+ \PolToSturm{f}{f}
+ \PolSturmIsolateZeros**{f}
+ \PolPrintIntervals{f}
+ \end{document}
+
+This takes more time than the polynomial with 1, 2, .., 20 as roots but
+less than the latter modified by the ``2**-23`` change in one
+coefficient.
+
+Here is the output (with release 0.7.2)::
+
+ Z_1 = 0.00000095367431640625
+ Z_2 = 0.0000019073486328125
+ Z_3 = 0.000003814697265625
+ Z_4 = 0.00000762939453125
+ Z_5 = 0.0000152587890625
+ Z_6 = 0.000030517578125
+ Z_7 = 0.00006103515625
+ Z_8 = 0.0001220703125
+ Z_9 = 1/4096
+ Z_10 = 1/2048
+ Z_11 = 1/1024
+ Z_12 = 1/512
+ Z_13 = 1/256
+ Z_14 = 1/128
+ Z_15 = 0.015625
+ Z_16 = 0.03125
+ Z_17 = 0.0625
+ Z_18 = 0.125
+ Z_19 = 0.25
+ Z_20 = 0.5
+
+There is some incoherence in output format which has its source in the
+fact that some roots are found in branches which can only find decimal
+roots, whereas some are found in branches which could find general
+fractions and they use ``\xintIrr`` before storage of the found root.
+This may evolve in future.
+
+
+The degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., 1.9, 2 as roots
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ \PolDef{P}{mul((x-i*1e-1), i=-20..20)}% i/10 is same but less efficient
+
+In the defining expression we could have used ``i/10`` but this gives
+less efficient internal form for the coefficients (the ``10``'s end up
+in denominators). Using ``\PolToExpr{P}`` after having done
+
+::
+
+ \renewcommand\PolToExprCmd[1]{\PolDecToString{\xintREZ{#1}}}
+
+we get this expanded form::
+
+ x^41
+ -28.7*x^39
+ +375.7117*x^37
+ -2975.11006*x^35
+ +15935.28150578*x^33
+ -61167.527674162*x^31
+ +173944.259366417394*x^29
+ -373686.963560544648*x^27
+ +613012.0665016658846445*x^25
+ -771182.31133138163125495*x^23
+ +743263.86672885754888959569*x^21
+ -545609.076599482896371978698*x^19
+ +301748.325708943677229642930528*x^17
+ -123655.8987669450434698869844544*x^15
+ +36666.1782054884005855608205864192*x^13
+ -7607.85821367459445649518380016128*x^11
+ +1053.15135918687298508885950223794176*x^9
+ -90.6380005918141132650786081964032*x^7
+ +4.33701563847327366842552218288128*x^5
+ -0.0944770968420804735498178265088*x^3
+ +0.00059190121813899276854174416896*x
+
+which shows coefficients with up to 36 significant digits...
+
+Stress test: not a hard challenge to ``xint + polexpr``, but be a bit patient!
+
+::
+
+ \PolDef{P}{mul((x-i*1e-1), i=-20..20)}%
+ \PolToSturm{P}{S} % dutifully computes S_0, ..., S_{41}
+ % the [1] optional argument limits the search to interval (-10,10)
+ \PolSturmIsolateZeros[1]{S} % finds *exactly* (but a bit slowly) all 41 roots!
+ \PolPrintIntervals{S} % nice, isn't it?
+
+.. note::
+
+ Release ``0.5`` has *experimental* addition of optional argument
+ ``E`` to ``\PolSturmIsolateZeros``. It instructs to search roots only
+ in interval ``(-10^E, 10^E)``. Important: the extremities are
+ *assumed to not be roots*. In this example, the ``[1]`` in
+ ``\PolSturmIsolateZeros[1]{S}`` gives some speed gain; without it, it
+ turns out in this case that ``polexpr`` would have started with
+ ``(-10^6, 10^6)`` interval.
+
+ Please note that this will probably get replaced in future by the
+ specification of a general interval. Do not rely on meaning of this
+ optional argument keeping the same.
+
+Roots of Chebyshev polynomials
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ \newcount\mycount
+ \poldef T_0(x) := 1;
+ \poldef T_1(x) := x;
+ \mycount 2
+ \xintloop
+ \poldef T_\the\mycount(x) :=
+ 2x*T_\the\numexpr\mycount-1(x)
+ - T_\the\numexpr\mycount-2(x);
+ \ifnum\mycount<15
+ \advance\mycount 1
+ \repeat
+
+ \[T_{15} = \PolTypeset[X]{T_15}\]
+ \PolToSturm{T_15}{T_15}
+ \PolSturmIsolateZeros{T_15}
+ \PolEnsureIntervalLengths{T_15}{-10}
+ \PolPrintIntervals{T_15}
+
+
+Non-expandable macros
+---------------------
+
+.. _poldef;:
+
+``\poldef polname(letter):= expression in letter;``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This evaluates the *polynomial expression* and stores the coefficients
+ in a private structure accessible later via other package macros,
+ under the user-chosen ``polname``. Of course the *expression* can
+ use other previously defined polynomials. Names must start with a
+ letter and are constituted of letters, digits, underscores and
+ (since ``0.5.1``) the right tick ``'``.
+ The whole xintexpr_ syntax is authorized::
+
+ \poldef sin(z) := add((-1)^i z^(2i+1)/(2i+1)!, i = 0..10);
+
+ With fractional coefficients, beware the `tacit multiplication issue
+ <warningtacit_>`_.
+
+ As a side effect the function ``polname()`` is recognized as a
+ genuine ``\xintexpr...\relax`` function for (exact) numerical
+ evaluation (or within an ``\xintdefvar`` assignment.) It computes
+ values not according to the original expression but via the Horner
+ scheme corresponding to the polynomial coefficients.
+
+ .. attention::
+
+ Release ``0.3`` also did the necessary set-up to let the
+ polynomial be known to the ``\xintfloatexpr`` (or
+ ``\xintdeffloatvar``) parser.
+
+ Since ``0.4`` this isn't done automatically. Even more, a
+ previously existing floating point variant of the same name will
+ be let undefined again, to avoid hard to debug mismatches between
+ exact and floating point polynomials. This also applies when the
+ polynomial is produced not via ``\poldef`` or ``\PolDef`` but as
+ a product of the other package macros.
+
+ See `\\PolGenFloatVariant{polname}`_.
+
+ The original expression is lost after parsing, and in particular
+ the package provides no way to typeset it. This has to be done
+ manually, if needed.
+
+.. _PolDef:
+
+``\PolDef[letter]{polname}{expression in letter}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Does the same as `\\poldef <poldef;>`_ in an undelimited macro
+ format (thus avoiding potential problems with the catcode of the
+ semi-colon in presence of some packages.) In absence of the
+ ``[letter]`` optional argument, the variable is assumed to be ``x``.
+
+.. _PolGenFloatVariant:
+
+``\PolGenFloatVariant{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Makes the polynomial also usable in the ``\xintfloatexpr`` parser.
+ It will therein evaluates via an Horner scheme with coefficients
+ already pre-rounded to the float precision.
+
+ See also `\\PolToFloatExpr{polname}`_.
+
+ .. attention::
+
+ Release ``0.3`` did this automatically on ``\PolDef`` and
+ ``\poldef`` but this was removed at ``0.4`` for optimization.
+
+ Any operation, for example generating the derivative polynomial,
+ or dividing two polynomials or using the ``\PolLet``, **must** be
+ followed by explicit usage of ``\PolGenFloatVariant{polname}`` if
+ the new polynomial is to be used in ``\xintfloatexpr`` or alike
+ context.
+
+.. _PolLet:
+
+``\PolLet{polname_2}={polname_1}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Makes a copy of the already defined polynomial ``polname_1`` to a
+ new one ``polname_2``. Same effect as
+ ``\PolDef{polname_2}{polname_1(x)}`` but with less overhead. The
+ ``=`` is optional.
+
+.. _PolGlobalLet:
+
+``\PolGlobalLet{polname_2}={polname_1}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Acts globally.
+
+.. _PolAssign:
+
+``\PolAssign{polname}\toarray\macro``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Defines a one-argument expandable macro ``\macro{#1}`` which expands
+ to the (raw) #1th polynomial coefficient.
+
+ - Attention, coefficients here are indexed starting at 1.
+
+ - With #1=-1, -2, ..., ``\macro{#1}`` returns leading coefficients.
+
+ - With #1=0, returns the number of coefficients, i.e. ``1 + deg f``
+ for non-zero polynomials.
+
+ - Out-of-range #1's return ``0/1[0]``.
+
+ See also `\\PolNthCoeff{polname}{number}`_. The main difference is that
+ with ``\PolAssign``, ``\macro`` is made a prefix to ``1 + deg f``
+ already defined (hidden to user) macros holding individually the
+ coefficients but `\\PolNthCoeff{polname}{number}`_ does each time the job
+ to expandably recover the ``Nth`` coefficient, and due to
+ expandability can not store it in a macro for future usage (of course,
+ it can be an argument in an ``\edef``.) The other difference
+ is the shift by one in indexing, mentioned above (negative
+ indices act the same in both.)
+
+.. _PolGet:
+
+``\PolGet{polname}\fromarray\macro``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Does the converse operation to
+ ``\PolAssign{polname}\toarray\macro``. Each individual
+ ``\macro{number}`` gets expanded in an ``\edef`` and then normalized
+ via xintfrac_\ 's macro ``\xintRaw``.
+
+ The leading zeros are removed from the polynomial.
+
+ (contrived) Example::
+
+ \xintAssignArray{1}{-2}{5}{-3}\to\foo
+ \PolGet{f}\fromarray\foo
+
+ This will define ``f`` as would have ``\poldef f(x):=1-2x+5x^2-3x^3;``.
+
+ .. note::
+
+ Prior to ``0.5``, coefficients were not normalized via
+ ``\xintRaw`` for internal storage.
+
+.. _PolFromCSV:
+
+``\PolFromCSV{polname}{<csv>}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Defines a polynomial directly from the comma separated list of values
+ (or a macro expanding to such a list) of its coefficients, the *first
+ item* gives the constant term, the *last item* gives the leading
+ coefficient, except if zero, then it is dropped (iteratively). List
+ items are each expanded in an ``\edef`` and then put into normalized
+ form via xintfrac_\ 's macro ``\xintRaw``.
+
+ As leading zero coefficients are removed::
+
+ \PolFromCSV{f}{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+ defines the zero polynomial, which holds only one coefficient.
+
+ See also expandable macro `\\PolToCSV <\\PolToCSV{polname}_>`_.
+
+ .. note::
+
+ Prior to ``0.5``, coefficients were not normalized via
+ ``\xintRaw`` for internal storage.
+
+.. _PolTypeset:
+
+``\PolTypeset{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Typesets in descending powers in math mode. It uses letter ``x`` but
+ this can be changed via an optional argument::
+
+ \PolTypeset[z]{polname}
+
+ By default zero coefficients are skipped (issue ``\poltypesetalltrue``
+ to get all of them in output).
+
+ These commands (whose meanings will be found in the package code)
+ can be re-defined for customization. Their default definitions are
+ expandable, but this is not a requirement.
+
+.. _PolTypesetCmd:
+
+``\PolTypesetCmd{raw_coeff}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Checks if the coefficient is ``1`` or ``-1`` and then skips printing
+ the ``1``, except for the constant term. Also it sets conditional
+ `\\PolIfCoeffIsPlusOrMinusOne{A}{B}`_.
+
+ The actual printing of the coefficients, when not equal to plus or
+ minus one is handled by `\\PolTypesetOne{raw_coeff}`_.
+
+.. _PolTypesetOne:
+
+``\PolTypesetOne{raw_coeff}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ The default is ``\xintSignedFrac`` but this macro is annoying as it
+ insists to use a power of ten, and not decimal notation.
+
+ One can do things such as for example: [#]_
+
+ ::
+
+ \renewcommand\PolTypesetOne[1]{\num{\xintPFloat[5]{#1}}}
+ \renewcommand\PolTypesetOne[1]{\num{\xintRound{4}{#1}}}
+
+ where e.g. we used the ``\num`` macro of ``siunitx`` as it
+ understands floating point notation.
+
+ .. [#] the difference in the syntaxes of ``\xintPFloat`` and
+ ``\xintRound`` is explained from the fact that
+ ``\xintPFloat`` by default uses the prevailing precision
+ hence the extra argument like here ``5`` is an optional one.
+
+ One can also give a try to using `\\PolDecToString{decimal number}`_
+ which uses decimal notation (at least for the numerator part).
+
+.. _PolTypesetMonomialCmd:
+
+``\PolTypesetMonomialCmd``
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ This decides how a monomial (in variable ``\PolVar`` and with
+ exponent ``\PolIndex``) is to be printed. The default does nothing
+ for the constant term, ``\PolVar`` for the first degree and
+ ``\PolVar^{\PolIndex}`` for higher degrees monomials. Beware that
+ ``\PolIndex`` expands to digit tokens and needs termination in
+ ``\ifnum`` tests.
+
+.. _PolTypesetCmdPrefix:
+
+``\PolTypesetCmdPrefix{raw_coeff}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Expands to a ``+`` if the ``raw_coeff`` is zero or positive, and to
+ nothing if ``raw_coeff`` is negative, as in latter case the
+ ``\xintSignedFrac`` used by `\\PolTypesetCmd{raw_coeff}`_ will put
+ the ``-`` sign in front of the fraction (if it is a fraction) and
+ this will thus serve as separator in the typeset formula. Not used
+ for the first term.
+
+.. _PolTypeset*:
+
+``\PolTypeset*{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Typesets in ascending powers. Use e.g. ``[h]`` optional argument
+ (after the ``*``) to use letter ``h`` rather than ``x``.
+
+.. _PolDiff:
+
+``\PolDiff{polname_1}{polname_2}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This sets ``polname_2`` to the first derivative of ``polname_1``. It
+ is allowed to issue ``\PolDiff{f}{f}``, effectively replacing ``f``
+ by ``f'``.
+
+ Coefficients of the result ``polname_2`` are irreducible fractions
+ (see `Technicalities`_ for the whole story.)
+
+.. _PolDiff[N]:
+
+``\PolDiff[N]{polname_1}{polname_2}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This sets ``polname_2`` to the ``N``-th derivative of ``polname_1``.
+ Identical arguments is allowed. With ``N=0``, same effect as
+ ``\PolLet{polname_2}={polname_1}``. With negative ``N``, switches to
+ using ``\PolAntiDiff``.
+
+.. _PolAntiDiff:
+
+``\PolAntiDiff{polname_1}{polname_2}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This sets ``polname_2`` to the primitive of ``polname_1`` vanishing
+ at zero.
+
+ Coefficients of the result ``polname_2`` are irreducible fractions
+ (see `Technicalities`_ for the whole story.)
+
+.. _PolAntiDiff[N]:
+
+``\PolAntiDiff[N]{polname_1}{polname_2}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This sets ``polname_2`` to the result of ``N`` successive integrations on
+ ``polname_1``. With negative ``N``, it switches to using ``\PolDiff``.
+
+.. _PolDivide:
+
+``\PolDivide{polname_1}{polname_2}{polname_Q}{polname_R}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This sets ``polname_Q`` and ``polname_R`` to be the quotient and
+ remainder in the Euclidean division of ``polname_1`` by
+ ``polname_2``.
+
+.. _PolQuo:
+
+``\PolQuo{polname_1}{polname_2}{polname_Q}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This sets ``polname_Q`` to be the quotient in the Euclidean division
+ of ``polname_1`` by ``polname_2``.
+
+.. _PolRem:
+
+``\PolRem{polname_1}{polname_2}{polname_R}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This sets ``polname_R`` to be the remainder in the Euclidean division
+ of ``polname_1`` by ``polname_2``.
+
+.. _PolGCD:
+
+``\PolGCD{polname_1}{polname_2}{polname_GCD}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This sets ``polname_GCD`` to be the (monic) GCD of the two first
+ polynomials. It is a unitary polynomial except if both ``polname_1``
+ and ``polname_2`` vanish, then ``polname_GCD`` is the zero
+ polynomial.
+
+.. ``\PolIGCD{polname_1}{polname_2}{polname_iGCD}``
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ **NOT YET**
+
+ This **assumes** that the two polynomials have integer coefficients.
+ It then computes the greatest common divisor in the integer
+ polynomial ring, normalized to have a positive leading coefficient
+ (if the inputs are not both zero).
+
+ ``\PolIContent{polname}``
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ **NOT YET**
+
+ This computes a positive rational number such that dividing the
+ polynomial with it returns an integer coefficients polynomial with
+ no common factor among the coefficients.
+
+.. _PolToSturm:
+
+``\PolToSturm{polname}{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ With ``polname`` being for example ``P``, the macro starts by
+ computing polynomials ``P`` and ``P'``, then computes the (opposite
+ of the) remainder in euclidean division, iteratively.
+
+ The last non-zero remainder ``P_N_`` (where ``N`` is obtainable as
+ `\\PolSturmChainLength{sturmname}`_) is up to a factor
+ the GCD of ``P`` and ``P'`` hence it is a constant if and only if
+ ``P`` is square-free.
+
+ .. note::
+
+ - Since ``0.5`` all these polynomials are divided by their rational
+ content, so they have integer coefficients with no common factor,
+ and the last one if a constant is either ``1`` or ``-1``.
+
+ - After this normalization to primitive polynomials, they are
+ stored internally as ``sturmname_k_``, ``k=0,1, ...``.
+
+ - These polynomials are used internally only. To keep them as
+ genuine declared polynomials also after the macro call, use the
+ starred variant `PolToSturm*`_.
+
+ .. note::
+
+ It is perfectly allowed to use the polynomial name as Sturm chain name:
+ ``\PolToSturm{f}(f}``.
+
+ The macro then declares ``sturmname_0``, ``sturmname_1``, ..., which are
+ the (non-declared) ``sturmname_k_`` divided by the last one. Division is
+ not done if this last one is the constant ``1`` or ``-1``, i.e. if the
+ original polynomial was square-free. These polynomials are primitive
+ polynomials too, i.e. with integer coefficients having no common factor.
+
+ Thus ``sturmname_0`` has exactly the same real and complex roots as
+ polynomial ``polname``, but with each root now of multiplicity one:
+ i.e. it is the "square-free part" of original polynomial ``polname``.
+
+ Notice that ``sturmname_1`` isn't necessarily the derivative of
+ ``sturmname_0`` due to the various normalizations.
+
+ The polynomials ``sturmname_k`` main utility is for the execution of
+ `\\PolSturmIsolateZeros{sturmname}`_. Be careful not to use these
+ names ``sturmname_0``, ``sturmname_1``, etc... for defining other
+ polynomials after having done ``\PolToSturm{polname}{sturmname}`` and
+ before executing ``\PolSturmIsolateZeros{sturmname}`` else the
+ latter will behave erroneously.
+
+ `\\PolSturmChainLength{sturmname}`_ gives the index of the last
+ element of the Sturm chain.
+
+.. _PolToSturm*:
+
+``\PolToSturm*{polname}{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Does the same as `un-starred version <PolToSturm_>`_ and additionally it
+ keeps for user usage the memory of the *un-normalized* Sturm chain
+ polynomials ``sturmname_k_``, ``k=0,1, ..., N``, with
+ ``N`` being `\\PolSturmChainLength{sturmname}`_.
+
+ .. note::
+
+ This behaviour was modified at ``0.6``, anyhow the macro was
+ broken at ``0.5``.
+
+ .. hint::
+
+ The square-free part of ``polname`` is ``sturmname_0``, and their
+ quotient is the polynomial with name
+ ``sturname_\PolSturmChainLength{sturmname}_``. It thus easy to
+ set-up a loop iteratively computing the latter until the last one
+ is a constant, thus obtaining the decomposition of an ``f`` as
+ a product ``c f_1 f_2 f_3 ...`` of a constant and square-free (primitive)
+ polynomials, where each ``f_i`` divides its predecessor.
+
+.. _PolSetToSturmChainSignChangesAt:
+
+``\PolSetToSturmChainSignChangesAt{\macro}{sturmname}{fraction}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Sets macro ``\macro`` to the number of sign changes in the Sturm
+ chain with name prefix ``sturmname``, at location ``fraction``
+ (which must be in format as acceptable by the xintfrac_ macros.)
+
+ .. note::
+
+ The author was lazy and did not provide rather an expandable
+ variant, where one would do ``\edef\macro{\PolNbOf...}``.
+
+ This will presumably get added in a future release.
+
+ After some hesitation it was decided the macro would by default
+ act globally. To make the scope of its macro definition local,
+ use ``[\empty]`` as extra optional argument.
+
+.. _PolSetToNbOfZerosWithin:
+
+``\PolSetToNbOfZerosWithin{\macro}{sturmname}{value_a}{value_b}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Applies the `Sturm Theorem`_ to set ``\macro`` to the exact number
+ of **distinct** roots of ``sturmname_0`` in the interval ``(value_a,
+ value_b]`` (the macro first re-orders the value for ``value_a <=
+ value_b`` to hold).
+
+ .. note::
+
+ The author was lazy and did not provide rather an expandable
+ variant, where one would do ``\edef\macro{\PolNbOf...}``.
+
+ This will presumably get added in future.
+
+ After some hesitation it was decided the macro would by default
+ act globally. To make the scope of its macro definition local,
+ use ``[\empty]`` as extra optional argument.
+
+ See also the expandable
+ `\\PolSturmNbOfRootsOf{sturmname}\\LessThanOrEqualTo{value}`_, from
+ which it is immediate (with ``\numexpr``) to create an expandable
+ variant of this macro. However the difference is that this macro
+ requires only `\\PolToSturm <PolToSturm_>`_ to have been executed,
+ whereas the expandable variant requires prior execution of
+ `\\PolSturmIsolateZeros <PolSturmIsolateZeros_>`_.
+
+ See also the expandable
+ `\\PolSturmNbWithMultOfRootsOf{sturmname}\\LessThanOrEqualTo{value}`_
+ which requires prior execution of
+ `\\PolSturmIsolateZeros* <PolSturmIsolateZeros*_>`_.
+
+
+.. _PolSturmIsolateZeros:
+
+``\PolSturmIsolateZeros{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The macros locates, using `Sturm theorem`_, as many disjoint
+ intervals as there are (real) roots.
+
+ .. important::
+
+ The Sturm chain must have been produced by an earlier
+ `\\PolToSturm{polname}{sturmname}`_.
+
+ Why does this macro ask for argument the name of Sturm chain,
+ rather than the name of a polynomial? well this is mainly for
+ legacy reason, and because it is accompanied by other macros for
+ which it is simpler to assume the argument will be the name of an
+ already computed Sturm chain.
+
+ Notice that ``\PolToSturm{f}{f}`` is perfectly legal (the
+ ``sturmname`` can be same as the ``polname``): it defines
+ polynomials ``f_0``, ``f_1``, ... having ``f`` has name prefix.
+
+ Such a prior call
+ to ``\PolToSturm`` must have been made at any rate for
+ ``\PolSturmIsolateZeros`` to be usable.
+
+ After its execution they are two types of such intervals (stored in
+ memory and accessible via macros or xintexpr_ variables, see below):
+
+ - singleton ``{a}``: then ``a`` is a root, (necessarily a decimal
+ number, but not all such decimal numbers are exactly identified yet).
+
+ - open intervals ``(a,b)``: then there is exactly one root ``z``
+ such that ``a < z < b``, and the end points are guaranteed to not
+ be roots.
+
+ The interval boundaries are decimal numbers, originating
+ in iterated decimal subdivision from initial intervals
+ ``(-10^E, 0)`` and ``(0, 10^E)`` with ``E`` chosen initially large
+ enough so that all roots are enclosed; if zero is a root it is always
+ identified as such. The non-singleton intervals are of the
+ type ``(a/10^f, (a+1)/10^f)`` with ``a`` an integer, which is
+ neither ``0`` nor ``-1``. Hence either ``a`` and ``a+1`` are both positive
+ or they are both negative.
+
+ One does not *a priori* know what will be the lengths of these
+ intervals (except that they are always powers of ten), they
+ vary depending on how many digits two successive roots have in
+ common in their respective decimal expansions.
+
+ .. important::
+
+ If some two consecutive intervals share an end-point, no
+ information is yet gained about the separation between the two
+ roots which could at this stage be arbitrarily small.
+
+ See `\\PolRefineInterval*{sturmname}{index}`_ which addresses
+ this issue.
+
+ .. This procedure is covariant
+ with the independent variable ``x`` becoming ``-x``.
+ Hmm, pas sûr et trop fatigué
+
+ The interval boundaries (and exactly found roots) are made available
+ for future computations in ``\xintexpr``-essions or polynomial
+ definitions as variables ``<sturmname>L_1``,
+ ``<sturmname>L_2``, etc..., for the left end-points and
+ ``<sturmname>R_1``, ``<sturmname>R_2``, ..., for the right
+ end-points.
+
+ Thus for example, if ``sturmname`` is ``f``, one can use the
+ xintexpr_ variables ``fL_1``, ``fL_2``, ... to refer in expressions
+ to the left end-points (or to the exact root, if left and right end
+ points coincide). Additionally, xintexpr_ variable ``fZ_1_isknown``
+ will have value ``1`` if the root in the first interval is known,
+ and ``0`` otherwise. And similarly for the other intervals.
+
+ Also, macros `\\PolSturmIsolatedZeroLeft{sturmname}{index}`_ and
+ `\\PolSturmIsolatedZeroRight{sturmname}{index}`_ are provided which
+ expand to these same values, written in decimal notation (i.e.
+ pre-processed by `\\PolDecToString <PolDecToString_>`_.) And there
+ is also `\\PolSturmIfZeroExactlyKnown{sturmname}{index}{A}{B}`_.
+
+ .. important::
+
+ Trailing zeroes in the stored decimal numbers accessible via the
+ macros are significant: they are also present in the decimal
+ expansion of the exact root.
+
+ These variables and macros are automatically updated when one next
+ uses macros such as `\\PolRefineInterval*{sturmname}{index}`_.
+
+ The start of decimal expansion of a positive ``k``-th root is given
+ by `\\PolSturmIsolatedZeroLeft{sturmname}{k}
+ <PolSturmIsolatedZeroLeft_>`_, and for a negative root it is given
+ by `\PolSturmIsolatedZeroRight{sturmname}{k}
+ <PolSturmIsolatedZeroRight_>`_. These two decimal
+ numbers are either both zero or both of the same sign.
+
+ The number of distinct roots is obtainable expandably as
+ `\\PolSturmNbOfIsolatedZeros{sturmname}`_.
+
+ Furthermore
+ `\\PolSturmNbOfRootsOf{sturmname}\\LessThanOrEqualTo{value}`_ and
+ `\\PolSturmNbOfRootsOf{sturmname}\\LessThanOrEqualToExpr{expression}`_.
+ will expandably compute respectively the number of real roots at
+ most equal to ``value`` or ``expression``, and the same but with
+ multiplicities.
+
+ .. note::
+
+ In the current implementation the xintexpr_ variables
+ and xinttools_ arrays are globally defined. On the
+ other hand the Sturm sequence polynomials obey the current scope.
+
+ .. note::
+
+ As all computations are done *exactly* there can be no errors...
+ apart those due to bad coding by author. The results are exact
+ bounds for the mathematically exact real roots.
+
+ Future releases will perhaps also provide macros based on Newton
+ or Regula Falsi methods. Exact computations with such methods
+ lead however quickly to very big fractions, and this forces usage
+ of some rounding scheme for the abscissas if computation times
+ are to remain reasonable. This raises issues of its own, which
+ are studied in numerical mathematics.
+
+.. _PolSturmIsolateZeros*:
+
+``\PolSturmIsolateZeros*{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The macro does the same as `\\PolSturmIsolateZeros{sturmname}`_ and
+ then in addition it does the extra work to determine all
+ multiplicities (of the real roots):
+ after executing this macro,
+ `\\PolSturmIsolatedZeroMultiplicity{sturmname}{index}`_ will expand
+ to the multiplicity of the root located in the ``index``\ -th
+ interval (intervals are enumerated from left to right, with index
+ starting at ``1``).
+
+ Furthermore, if for example the ``sturmname`` is ``f``, xintexpr_
+ variables ``fM_1``, ``fM_2``... hold the multiplicities thus
+ computed.
+
+ .. note::
+
+ It is **not** necessary to have executed the `PolToSturm*`_ starred
+ variant, as the non-starred variant keeps internally the memory of the
+ original GCD (and even of the full non-normalized original Sturm
+ chain), even though it does not make the declarations as *user-level*
+ genuine polynomials.
+
+ See `The degree nine polynomial with 0.99, 0.999, 0.9999 as triple
+ roots`_ for an example.
+
+.. _PolSturmIsolateZeros**:
+
+``\PolSturmIsolateZeros**{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The macro does the same as `\\PolSturmIsolateZeros*{sturmname}`_ and
+ in addition it does the extra work to determine all the *rational*
+ roots.
+
+ .. note::
+
+ After execution of this macro, a root is "known" if and only if
+ it is rational.
+
+ Furthermore, primitive polynomial ``sturmname_sqf_norr`` is created
+ to match the (square-free) ``sturmname_0`` from which all rational
+ roots have been removed (see `\\polexprsetup`_ for customizing this
+ name). The number of distinct rational roots is thus the difference
+ between the degrees of these two polynomials (see also
+ `\\PolSturmNbOfRationalRoots{sturmname}`_).
+
+ And ``sturmname_norr`` is ``sturmname_0_`` from which all rational
+ roots have been removed (see `\\polexprsetup`_), i.e. it contains
+ the irrational roots of the original polynomial, with the same
+ multiplicities.
+
+ See `A degree five polynomial with three rational
+ roots`_ for an example.
+
+.. _PolSturmIsolateZerosAndGetMultiplicities:
+
+``\PolSturmIsolateZerosAndGetMultiplicities{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This is another name for `\\PolSturmIsolateZeros*{sturmname}`_.
+
+.. _PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots:
+
+``\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This is another name for `\\PolSturmIsolateZeros**{sturmname}`_.
+
+
+``\PolSturmIsolateZerosAndFindRationalRoots{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This works exactly like `\\PolSturmIsolateZeros**{sturmname}`_
+ (inclusive of declaring the polynomials ``sturmname_sqf_norr`` and
+ ``sturmname_norr`` with no rational roots) except that it does *not*
+ compute the multiplicities of the *non-rational* roots.
+
+ .. note::
+
+ There is no macro to find the rational roots but not compute
+ their multiplicities at the same time.
+
+ .. attention::
+
+ This macro does *not* define xintexpr_ variables
+ ``sturmnameM_1``, ``sturmnameM_2``, ... holding the
+ multiplicities and it leaves the multiplicity array (whose accessor
+ is `\\PolSturmIsolatedZeroMultiplicity{sturmname}{index}`_) into
+ a broken state, as all non-rational roots will supposedly have
+ multiplicity one. This means that the output of
+ `\\PolPrintIntervals* <PolPrintIntervals*_>`_ for example will be
+ erroneous for the intervals with irrational roots.
+
+ I decided to document it because finding multiplicities of the
+ non rational roots is somewhat costly, and one may be interested
+ only into finding the rational roots (of course random
+ polynomials with integer coefficients will not have *any*
+ rational root anyhow).
+
+
+.. _PolRefineInterval*:
+
+``\PolRefineInterval*{sturmname}{index}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The ``index``\ -th interval (starting indexing at one) is further
+ subdivided as many times as is necessary in order for the newer
+ interval to have both its end-points distinct from the end-points of
+ the original interval. This means that the ``k``\ th root is then
+ strictly separated from the other roots.
+
+.. _PolRefineInterval[N]:
+
+``\PolRefineInterval[N]{sturmname}{index}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The ``index``\ -th interval (starting count at one) is further
+ subdivided once, reducing its length by a factor of 10. This is done
+ ``N`` times if the optional argument ``[N]`` is present.
+
+.. _PolEnsureIntervalLength:
+
+``\PolEnsureIntervalLength{sturmname}{index}{E}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The ``index``\ -th interval is subdivided until its length becomes at
+ most ``10^E``. This means (for ``E<0``) that the first ``-E`` digits
+ after decimal mark of the ``k``\ th root will then be known exactly.
+
+.. _PolEnsureIntervalLengths:
+
+``\PolEnsureIntervalLengths{sturmname}{E}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The intervals as obtained from ``\PolSturmIsolateZeros`` are (if
+ necessary) subdivided further by (base 10) dichotomy in order for
+ each of them to have length at most ``10^E`` (length will be shorter
+ than ``10^E`` in output only if it did not change or became zero.)
+
+ This means that decimal expansions of all roots will be known with
+ ``-E`` digits (for ``E<0``) after decimal mark.
+
+.. _PolPrintIntervals:
+
+``\PolPrintIntervals[varname]{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This is a convenience macro which prints the bounds for the roots
+ ``Z_1``, ``Z_2``, ... (the optional argument ``varname`` allows to
+ specify a replacement for the default ``Z``). This will be done (by
+ default) in a
+ math mode ``array``, one interval per row, and pattern ``rcccl``,
+ where the second and fourth column hold the ``<`` sign, except when
+ the interval reduces to a singleton, which means the root is known
+ exactly.
+
+ .. attention::
+
+ This macro was refactored at 0.7, its default output remained
+ identical but the ways to customize it got completely
+ modified.
+
+ See next macros which govern its output.
+
+``\PolPrintIntervalsNoRealRoots``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Executed in place of an ``array`` environment, when there are no
+ real roots. Default definition::
+
+ \newcommand\PolPrintIntervalsNoRealRoots{}
+
+``\PolPrintIntervalsBeginEnv``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Default definition::
+
+ \newcommand\PolPrintIntervalsBeginEnv{\[\begin{array}{rcccl}}
+
+``\PolPrintIntervalsEndEnv``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Default definition::
+
+ \newcommand\PolPrintIntervalsEndEnv{\end{array}\]}
+
+``\PolPrintIntervalsKnownRoot``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Default definition::
+
+ \newcommand\PolPrintIntervalsKnownRoot{%
+ &&\PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}%
+ &=&\PolPrintIntervalsPrintExactZero
+ }
+
+``\PolPrintIntervalsUnknownRoot``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Default definition::
+
+ \newcommand\PolPrintIntervalsUnknownRoot{%
+ \PolPrintIntervalsPrintLeftEndPoint&<&%
+ \PolPrintIntervalsTheVar_{\PolPrintIntervalsTheIndex}&<&%
+ \PolPrintIntervalsPrintRightEndPoint
+ }
+
+
+.. _PolPrintIntervalsPrintExactZero:
+
+``\PolPrintIntervalsPrintExactZero``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Default definition::
+
+ \newcommand\PolPrintIntervalsPrintExactZero{\PolPrintIntervalsTheLeftEndPoint}
+
+
+.. _PolPrintIntervalsPrintLeftEndPoint:
+
+``\PolPrintIntervalsPrintLeftEndPoint``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Default definition::
+
+ \newcommand\PolPrintIntervalsPrintLeftEndPoint{\PolPrintIntervalsTheLeftEndPoint}
+
+.. _PolPrintIntervalsPrintRightEndPoint:
+
+``\PolPrintIntervalsPrintRightEndPoint``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Default definition is::
+
+ \newcommand\PolPrintIntervalsPrintRightEndPoint{\PolPrintIntervalsTheRightEndPoint}
+
+.. _PolPrintIntervals*:
+
+``\PolPrintIntervals*[varname]{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This starred variant produces an alternative output (which
+ displays the root multiplicity), and is provided as an
+ example of customization.
+
+ As replacement for `\\PolPrintIntervalsKnownRoot`_,
+ `\\PolPrintIntervalsPrintExactZero`_,
+ `\\PolPrintIntervalsUnknownRoot`_ it uses its own
+ ``\POL@@PrintIntervals...`` macros. We only reproduce here one
+ definition::
+
+ \newcommand\POL@@PrintIntervalsPrintExactZero{%
+ \displaystyle
+ \xintSignedFrac{\PolPrintIntervalsTheLeftEndPoint}%
+ }%
+
+ Multiplicities are printed using this auxiliary macro:
+
+``\PolPrintIntervalsPrintMultiplicity``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ whose default definition is::
+
+ \newcommand\PolPrintIntervalsPrintMultiplicity{(\mbox{mult. }\PolPrintIntervalsTheMultiplicity)}
+
+
+.. _PolMapCoeffs:
+
+``\PolMapCoeffs{\macro}{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ It modifies ('in-place': original coefficients get lost) each
+ coefficient of the defined polynomial via the *expandable* macro
+ ``\macro``. The degree is adjusted as necessary if some leading
+ coefficients vanish after the operation. In replacement text of
+ ``\macro``, ``\index`` expands to the coefficient index (which is
+ defined to be zero for the constant term).
+
+ Notice that ``\macro`` will have to handle inputs of the shape
+ ``A/B[N]`` (xintfrac_ internal notation). This means that it probably
+ will have to be expressed in terms of macros from xintfrac_ package.
+
+ Example::
+
+ \def\foo#1{\xintMul{#1}{\the\numexpr\index*\index\relax}}
+
+ (or with ``\xintSqr{\index}``) to replace ``n``-th coefficient
+ ``f_n`` by ``f_n*n^2``.
+
+.. _PolReduceCoeffs:
+
+``\PolReduceCoeffs{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ About the same as ``\PolMapCoeffs{\xintIrr}{polname}`` (but
+ maintaining a ``[0]`` postfix for speedier xintfrac_ parsing when
+ polynomial function is used for computations.) This is a
+ one-argument macro, working 'in-place'.
+
+.. _PolReduceCoeffs*:
+
+``\PolReduceCoeffs*{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This starred variant leaves un-touched the decimal exponent in the
+ internal representation of the fractional coefficients, i.e. if a
+ coefficient is internally ``A/B[N]``, then ``A/B`` is reduced to
+ smallest terms, but the ``10^N`` part is kept as is. Note: if the
+ polynomial is freshly defined directly via `\\PolFromCSV
+ <PolFromCSV_>`_ its coefficients might still be internally in some
+ format like ``1.5e7``; the macro will anyhow always first do the
+ needed conversion to strict format ``A/B[N]``.
+
+ Evaluations with polynomials treated by this can be much faster than
+ with those handled by the non-starred variant
+ `\\PolReduceCoeffs{polname}`_: as the numerators and denominators
+ remain smaller, this proves very beneficial in favorable cases
+ (especially when the coefficients are decimal numbers) to the
+ expansion speed of the xintfrac_ macros used internally by
+ `\\PolEval <PolEvalAt_>`_.
+
+.. _PolMakeMonic:
+
+``\PolMakeMonic{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Divides by the leading coefficient. It is recommended to execute
+ `\\PolReduceCoeffs*{polname}`_ immediately afterwards. This is not
+ done automatically, due to the case the original polynomial had integer
+ coefficients and we want to keep the leading one as common
+ denominator.
+
+.. _PolMakePrimitive:
+
+``\PolMakePrimitive{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Divides by the integer content see (`\\PolIContent
+ <PolIContent_>`_). This thus produces a polynomial with integer
+ coefficients having no common factor. The sign of the leading
+ coefficient is not modified.
+
+Expandable macros
+-----------------
+
+All these macros expand completely in two steps except ``\PolToExpr``
+and ``\PolToFloatExpr`` (and their auxiliaries) which need a
+``\write``, ``\edef`` or a ``\csname...\endcsname`` context.
+
+.. _PolEvalAtExpr:
+
+``\PolEval{polname}\AtExpr{numerical expression}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ It boils down to
+ ``\xinttheexpr polname(numerical expression)\relax``.
+
+.. _PolEvalAt:
+
+``\PolEval{polname}\At{fraction}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Evaluates the polynomial at value ``fraction`` which must be in (or
+ expand to) a format acceptable to the xintfrac_ macros.
+
+.. _PolEvalReducedAtExpr:
+
+``\PolEvalReduced{polname}\AtExpr{numerical expression}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Boils down to ``\xinttheexpr reduce(polname(numerical expression))\relax``.
+
+.. _PolEvalReducedAt:
+
+``\PolEvalReduced{polname}\At{fraction}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Evaluates the polynomial at value ``fraction`` which must be in (or
+ expand to) a format acceptable to the xintfrac_ macros, and produce
+ an irreducible fraction.
+
+.. _PolFloatEvalAtExpr:
+
+``\PolFloatEval{polname}\AtExpr{numerical expression}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Boils down to ``\xintthefloatexpr polname(numerical expression)\relax``.
+
+ This is done via a Horner Scheme (see `\\poldef <poldef;_>`_ and
+ `\\PolGenFloatVariant{polname}`_), with already rounded
+ coefficients. [#]_ To use the *exact coefficients* with *exactly
+ executed* additions and multiplications, just insert it in the float
+ expression as in this example: [#]_
+
+ ::
+
+ \xintthefloatexpr 3.27*\xintexpr f(2.53)\relax^2\relax
+
+ The ``f(2.53)`` is exactly computed then rounded at the time of
+ getting raised to the power ``2``. Moving the ``^2`` inside, that
+ operation would also be treated exactly.
+
+
+ .. [#] Anyway each floating point operation starts by rounding its
+ operands to the floating point precision.
+
+ .. [#] The ``\xintexpr`` here could be ``\xinttheexpr`` but that
+ would be less efficient. Cf. xintexpr_ documentation about
+ nested expressions.
+
+.. _PolFloatEvalAt:
+
+``\PolFloatEval{polname}\At{fraction}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Evaluates the polynomial at value ``fraction`` which must be in (or
+ expand to) a format acceptable to the xintfrac_ macros, and produces
+ a floating point number.
+
+.. _PolIfCoeffIsPlusOrMinusOne:
+
+``\PolIfCoeffIsPlusOrMinusOne{A}{B}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This macro is a priori undefined.
+
+ It is defined via the default `\\PolTypesetCmd{raw_coeff}`_ to be
+ used if needed in the execution of `\\PolTypesetMonomialCmd`_,
+ e.g. to insert a ``\cdot`` in front of ``\PolVar^{\PolIndex}`` if
+ the coefficient is not plus or minus one.
+
+ The macro will execute ``A`` if the coefficient has been found to be
+ plus or minus one, and ``B`` if not.
+
+.. _PolLeadingCoeff:
+
+``\PolLeadingCoeff{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to the leading coefficient.
+
+.. _PolNthCoeff:
+
+``\PolNthCoeff{polname}{number}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ It expands to the raw ``N``-th coefficient (``0/1[0]`` if the index
+ number is out of range). With ``N=-1``, ``-2``, ... expands to the
+ leading coefficients.
+
+.. _PolDegree:
+
+``\PolDegree{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+ It expands to the degree. This is ``-1`` if zero polynomial but this
+ may change in future. Should it then expand to ``-\infty`` ?
+
+.. _PolIContent:
+
+``\PolIContent{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ It expands to the contents of the polynomial, i.e. to the positive
+ fraction such that dividing by this fraction produces a polynomial
+ with integer coefficients having no common prime divisor.
+
+ See `\\PolMakePrimitive <PolMakePrimitive_>`_.
+
+.. _PolToExpr:
+
+``\PolToExpr{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands [#]_ to ``coeff_N*x^N+...`` (descending powers.)
+
+ .. [#] in a ``\write``, ``\edef``, or ``\csname...\endcsname``, but
+ not under ``\romannumeral-`0``.
+
+ By default zero coefficients are skipped (issue ``\poltoexpralltrue`` to
+ get all of them in output).
+
+ By default, no ``+`` sign before negative coefficients, for
+ compliance with Maple input format (but see
+ `\\PolToExprTermPrefix{raw_coeff}`_.) Also, like the default
+ behaviour of `\\PolTypeset{polname}`_, does not print (for the non
+ constant terms) coefficients equal to plus or minus one. The degree
+ one monomial is output as ``x``, not ``x^1``. Complete customization is
+ possible, see next macros.
+
+ Of course ``\PolToExpr{f}`` can be inserted in a ``\poldef``, as the
+ latter expands token by token, hence will force complete expansion
+ of ``\PolToExpr{f}``, but a simple ``f(x)`` is more efficient for
+ the identical result.
+
+.. _PolToExprOneTerm:
+
+``\PolToExprOneTerm{raw_coeff}{number}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ This two argument expandable command takes care of the monomial and
+ its coefficient. The default definition is done in order for
+ coefficients of absolute value ``1`` not be printed explicitely
+ (except of course for the constant term). Also by default, the
+ monomial of degree one is ``x`` not ``x^1``, and ``x^0`` is skipped.
+
+ For compatibility with Maple input requirements, by default a ``*``
+ always precedes the ``x^number``, except if the coefficient is a one
+ or a minus one. See `\\PolToExprTimes`_.
+
+.. _PolToExprOneTermStyleA:
+
+``\PolToExprOneTermStyleA{raw_coeff}{number}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Holds the default package meaning of
+ `\\PolToExprOneTerm{raw_coeff}{number}`_.
+
+.. _PolToExprOneTermStyleB:
+
+``\PolToExprOneTermStyleB{raw_coeff}{number}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ For output in this style::
+
+ 2*x^11/3+3*x^8/7-x^5-x^4/4-x^3-x^2/2-2*x+1
+
+ issue ``\let\PolToExprOneTerm\PolToExprOneTermStyleB`` before usage of
+ ``\PolToExpr``. Note that then ``\PolToExprCmd`` isn't used at all.
+ To revert to package default, issue
+ ``\let\PolToExprOneTerm\PolToExprOneTermStyleA``.
+
+ To suppress the ``*``'s, cf. `\\PolToExprTimes`_.
+
+.. _PolToExprCmd:
+
+``\PolToExprCmd{raw_coeff}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ It is the one-argument macro used by the package definition of
+ ``\PolToExprOneTerm`` for the coefficients themselves (when not
+ equal to plus or minus one), and it defaults to
+ ``\xintPRaw{\xintRawWithZeros{#1}}``. One will have to redefine it
+ to ``\xintIrr{#1}`` or to ``\xintPRaw{\xintIrr{#1}}`` to obtain in the
+ output forcefully reduced coefficients.
+
+.. _PolToExprTermPrefix:
+
+``\PolToExprTermPrefix{raw_coeff}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Defined identically as `\\PolTypesetCmdPrefix{raw_coeff}`_. It
+ prefixes with a plus sign for non-negative coefficients, because
+ they don't carry one by themselves.
+
+.. _PolToExprVar:
+
+``\PolToExprVar``
+^^^^^^^^^^^^^^^^^
+
+ This expands to the variable to use in output (it does not have to
+ be a single letter, may be an expandable macro.) Initial definition
+ is ``x``.
+
+.. _PolToExprTimes:
+
+``\PolToExprTimes``
+^^^^^^^^^^^^^^^^^^^
+
+ This expands to the symbol used for multiplication of an
+ ``x^{number}`` by the corresponding coefficient. The default is
+ ``*``. Redefine the macro to expand to nothing to get rid of it (but
+ this will give output incompatible with some professional computer
+ algebra software).
+
+.. _PolToExpr*:
+
+``\PolToExpr*{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to ``coeff_0+coeff_1*x+coeff_2*x^2+...`` (ascending powers).
+ Customizable like `\\PolToExpr{polname}`_ via the same macros.
+
+.. _PolToFloatExpr:
+
+``\PolToFloatExpr{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Similar to `\\PolToExpr{polname}`_ but uses `\\PolToFloatExprCmd
+ <\\PolToFloatExprCmd{raw_coeff}>`_
+ which by default rounds and converts the coefficients to floating
+ point format.
+
+ .. note::
+
+ It is not necessary to have issued
+ `\\PolGenFloatVariant{polname}`_. The rounded coefficients are
+ not easily recoverable from the ``\xintfloatexpr`` polynomial
+ function hence ``\PolToFloatExprCmd`` operates from the *exact*
+ coefficients anew.
+
+ Attention that both macros obey the prevailing float precision.
+ If it is changed between those macro calls, then a mismatch
+ exists between the coefficients as used in ``\xintfloatexpr`` and
+ those output by ``\PolToFloatExpr{polname}``.
+
+.. _PolToFloatExprOneTerm:
+
+``\PolToFloatExprOneTerm{raw_coeff}{number}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Similar to `\\PolToExprOneTerm
+ <\\PolToExprOneTerm{raw_coeff}{number}>`_. But does not treat
+ especially coefficients equal to plus or minus one.
+
+.. _PolToFloatExprCmd:
+
+``\PolToFloatExprCmd{raw_coeff}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ It is the one-argument macro used by ``\PolToFloatExprOneTerm``.
+ Its package definition is ``\xintFloat{#1}``.
+
+ .. caution::
+
+ Currently (xint_ ``1.3c``) ``\xintFloat{0}`` outputs ``0.e0``
+ which is perfectly acceptable input for Python, but not for
+ Maple. Thus, one should better leave the `\\poltoexprallfalse`_
+ toggle to its default ``\iffalse`` state, if one intends to use
+ the output in a Maple worksheet.
+
+ But even then the zero polynomial will cause a problem. Workaround::
+
+ \renewcommand\PolToFloatExprCmd[1]{\xintiiifZero{#1}{0.0}{\xintFloat{#1}}}
+
+ Usage of ``\xintiiifZero`` and not ``\xintifZero`` is only for
+ optimization (I can't help it) because ``#1`` is known to be
+ in ``xintfrac`` raw format.
+
+.. _PolToFloatExpr*:
+
+``\PolToFloatExpr*{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Typesets in ascending powers.
+
+.. _PolToList:
+
+``\PolToList{polname}``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to ``{coeff_0}{coeff_1}...{coeff_N}`` with ``N`` = degree, and
+ ``coeff_N`` the leading coefficient
+ (the zero polynomial does give ``{0/1[0]}`` and not an
+ empty output.)
+
+.. _PolToCSV:
+
+``\PolToCSV{polname}``
+~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to ``coeff_0, coeff_1, coeff_2, ....., coeff_N``, starting
+ with constant term and ending with leading coefficient. Converse
+ to `\\PolFromCSV <\\PolFromCSV{polname}{\<csv\>}_>`_.
+
+.. _PolSturmChainLength:
+
+``\PolSturmChainLength{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Returns the integer ``N`` such that ``sturmname_N`` is the last one
+ in the Sturm chain ``sturmname_0``, ``sturmname_1``, ...
+
+ See `\\PolToSturm{polname}{sturmname}`_.
+
+.. _PolSturmIfZeroExactlyKnown:
+
+``\PolSturmIfZeroExactlyKnown{sturmname}{index}{A}{B}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Executes ``A`` if the ``index``\ -th interval reduces to a singleton,
+ i.e. the root is known exactly, else ``B``.
+
+ .. note::
+
+ ``index`` is allowed to be something like ``1+2*3`` as it is fed
+ to ``\the\numexpr...\relax``.
+
+.. _PolSturmIsolatedZeroLeft:
+
+``\PolSturmIsolatedZeroLeft{sturmname}{index}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to the left end-point for the ``index``\ -th interval, as
+ computed by some earlier `\\PolSturmIsolateZeros{sturmname}`_.
+
+ .. note::
+
+ Of course, this is kept updated by macros such as
+ `\\PolRefineInterval{sturmname}{index} <PolRefineInterval[N]_>`_.
+
+ The value is pre-formatted using `\\PolDecTostring
+ <PolDecToString_>`_.
+
+.. _PolSturmIsolatedZeroRight:
+
+``\PolSturmIsolatedZeroRight{sturmname}{index}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to the right end-point for the ``index``\ -th interval as
+ computed by some earlier `\\PolSturmIsolateZeros{sturmname}`_ and
+ possibly refined afterwards.
+
+ The value is pre-formatted using `\\PolDecTostring
+ <PolDecToString_>`_.
+
+.. _PolSturmIsolatedZeroMultiplicity:
+
+``\PolSturmIsolatedZeroMultiplicity{sturmname}{index}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to the multiplicity of the unique root contained in the
+ ``index``\ -th interval.
+
+ .. attention::
+
+ A prior execution of `\\PolSturmIsolateZeros*{sturmname}`_ is mandatory.
+
+ See `The degree nine polynomial with 0.99, 0.999, 0.9999 as triple
+ roots`_ for an example of use.
+
+.. _PolSturmNbOfIsolatedZeros:
+
+``\PolSturmNbOfIsolatedZeros{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to the number of real roots of the polynomial
+ ``<sturmname>_0``, i.e. the number of distinct real roots of the
+ polynomial originally used to create the Sturm chain via
+ `\\PolToSturm{polname}{sturmname}`_.
+
+.. warning::
+
+ The next few macros counting roots, with or without multiplicities,
+ less than or equal to some value, are under evaluation and may be
+ removed from the package if their utility is judged to be not high
+ enough. They can be re-coded at user level on the basis of the other
+ documented package macros anyway.
+
+``\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualTo{value}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Expands to the number of distinct roots (of the polynomial used to
+ create the Sturm chain) less than or equal to the ``value`` (i.e. a
+ number of fraction recognizable by the xintfrac_ macros).
+
+ .. attention::
+
+ `\\PolSturmIsolateZeros{sturmname}`_ must have been executed
+ beforehand.
+
+ And the argument is a ``sturmname``, not a ``polname`` (this is
+ why the macro contains Sturm in its name), simply to be reminded
+ of the above constraint.
+
+``\PolSturmNbOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Expands to the number of distinct roots (of the polynomial
+ used to create the Sturm chain) which are less than or equal to the
+ given ``expression``.
+
+ .. attention::
+
+ `\\PolSturmIsolateZeros{sturmname}`_ must have been executed
+ beforehand.
+
+``\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualTo{value}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Expands to the number counted with multiplicities of the roots (of
+ the polynomial used to create the Sturm chain) which are less than
+ or equal to the given ``value``.
+
+ .. attention::
+
+ `\\PolSturmIsolateZeros*{sturmname}`_ (or the double starred
+ variant) must have been executed beforehand.
+
+``\PolSturmNbWithMultOfRootsOf{sturmname}\LessThanOrEqualToExpr{expression}``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Expands to the total number of roots (counted with multiplicities)
+ which are less than or equal to the given ``expression``.
+
+ .. attention::
+
+ `\\PolSturmIsolateZeros*{sturmname}`_ (or the double starred
+ variant) must have been executed beforehand.
+
+``\PolSturmNbOfRationalRoots{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to the number of rational roots (without multiplicities).
+
+ .. attention::
+
+ `\\PolSturmIsolateZeros**{sturmname}`_ must have been executed
+ beforehand.
+
+``\PolSturmNbOfRationalRootsWithMultiplicities{sturmname}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to the number of rational roots (counted with multiplicities).
+
+ .. attention::
+
+ `\\PolSturmIsolateZeros**{sturmname}`_ must have been executed
+ beforehand.
+
+``\PolSturmRationalRoot{sturmname}{k}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to the ``k``\ th rational root (they are ordered and indexed
+ starting at 1 for the most negative).
+
+ .. attention::
+
+ `\\PolSturmIsolateZeros**{sturmname}`_ must have been executed
+ beforehand.
+
+``\PolSturmRationalRootIndex{sturmname}{k}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to ``index`` of the ``k``\ th rational root as part of the
+ ordered real roots (without multiplicities). I.e., above macro
+ `\\PolSturmRationalRoot{sturmname}{k}`_ is equivalent to this
+ nested call::
+
+ \PolSturmIsolatedZeroLeft{sturmname}{\PolSturmRationalRootIndex{sturmname}{k}}
+
+ .. attention::
+
+ `\\PolSturmIsolateZeros**{sturmname}`_ must have been executed
+ beforehand.
+
+``\PolSturmRationalRootMultiplicity{sturmname}{k}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Expands to the multiplicity of the ``k``\ th rational root.
+
+ .. attention::
+
+ `\\PolSturmIsolateZeros**{sturmname}`_ must have been executed
+ beforehand.
+
+.. _PolIntervalWidth:
+
+``\PolIntervalWidth{sturmname}{index}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ The ``10^E`` width of the current ``index``\ -th root localization
+ interval. Output is in xintfrac_ raw ``1/1[E]`` format (if not zero).
+
+Expandable macros for use within execution of ``\PolPrintIntervals``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These macros are for usage within custom user redefinitions of
+`\\PolPrintIntervalsKnownRoot`_, `\\PolPrintIntervalsUnknownRoot`_, or
+in redefinitions of `\PolPrintIntervalsPrintExactZero`_ (used in the
+default for the former) and of `\\PolPrintIntervalsPrintLeftEndPoint`_,
+`\\PolPrintIntervalsPrintRightEndPoint`_ (used in the default for the
+latter).
+
+.. attention::
+
+ Some macros formerly mentioned here got removed at 0.7:
+ ``\PolPrintIntervalsTheEndPoint``,
+ ``\PolIfEndPointIsPositive{A}{B}``,
+ ``\PolIfEndPointIsNegative{A}{B}``,
+ ``\PolIfEndPointIsZero{A}{B}``.
+
+``\PolPrintIntervalsTheVar``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Expands to the name (default ``Z``) used for representing the roots,
+ which was passed as optional argument ``varname`` to
+ `\\PolPrintIntervals[varname]{sturmname}`_.
+
+``\PolPrintIntervalsTheIndex``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Expands to the index of the considered interval (indexing starting
+ at 1 for the leftmost interval).
+
+``\PolPrintIntervalsTheSturmName``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ Expands to the argument which was passed as ``sturmname`` to
+ `\\PolPrintIntervals[varname]{sturmname}`_.
+
+``\PolPrintIntervalsTheLeftEndPoint``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ The left end point of the interval, as would be produced by
+ `\\PolSturmIsolatedZeroLeft <PolSturmIsolatedZeroLeft_>`_ if it was
+ used with arguments the Sturm chain name and interval index returned
+ by `\\PolPrintIntervalsTheSturmName`_ and
+ `\\PolPrintIntervalsTheIndex`_.
+
+``\PolPrintIntervalsTheRightEndPoint``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ The right end point of the interval, as would be produced by
+ `\\\PolSturmIsolatedZeroRight <PolSturmIsolatedZeroRight_>`_ for
+ this Sturm chain name and index.
+
+``\PolPrintIntervalsTheMultiplicity``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ The multiplicity of the unique root within the interval of index
+ `\\PolPrintIntervalsTheIndex`_. Makes sense only if the starred (or
+ double-starred) variant of `\\PolSturmIsolateZeros
+ <PolSturmIsolateZeros_>`_ was used earlier.
+
+.. _PolDecToString:
+
+``\PolDecToString{decimal number}``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ This is a utility macro to print decimal numbers. It has been
+ backported to xintfrac_ (release ``1.3`` of ``2018/03/01``) under
+ the name ``\xintDecToString``, and the ``polexpr`` macro is simply
+ now an alias to it.
+
+ For example
+ ``\PolDecToString{123.456e-8}`` will expand to ``0.00000123456``
+ and ``\PolDecToString{123.450e-8}`` to ``0.00000123450`` which
+ illustrates that trailing zeros are not trimmed. To trim trailing
+ zeroes, one can use ``\PolDecToString{\xintREZ{#1}}``.
+
+ The precise behaviour of this macro may evolve in future releases of
+ xint_.
+
+Booleans (with default setting as indicated)
+--------------------------------------------
+
+``\xintverbosefalse``
+~~~~~~~~~~~~~~~~~~~~~
+
+ This is actually an xintexpr_ configuration. Setting it to
+ ``true`` triggers the writing of information to the log when new
+ polynomials are defined.
+
+ .. caution::
+
+ The macro meanings as written to the log are to be considered
+ unstable and undocumented internal structures.
+
+``\poltypesetallfalse``
+~~~~~~~~~~~~~~~~~~~~~~~
+
+ If ``true``, `\\PolTypeset{polname}`_ will also typeset the vanishing
+ coefficients.
+
+
+``\poltoexprallfalse``
+~~~~~~~~~~~~~~~~~~~~~~
+
+ If ``true``, `\\PolToExpr{polname}`_ and `\\PolToFloatExpr{polname}`_ will
+ also include the vanishing coefficients in their outputs.
+
+``\polexprsetup``
+-----------------
+
+ Serves to customize the package. Currently only two keys are
+ recognized:
+
+ - ``norr``: the postfix that `\\PolSturmIsolateZeros**{sturmname}`_
+ should append to ``sturmname`` to declare the primitive polynomial
+ obtained from original one after removal of all rational roots.
+ The default value is ``_norr`` (standing for “no rational roots”).
+
+ - ``sqfnorr``: the postfix that `\\PolSturmIsolateZeros**{sturmname}`_
+ should append to ``sturmname`` to declare the primitive polynomial
+ obtained from original one after removal of all rational roots and
+ suppression of all multiplicities.
+ The default value is ``_sqf_norr`` (standing for “square-free with
+ no rational roots”).
+
+ The package executes ``\polexprsetup{norr=_norr,
+ sqfnorr=_sqf_norr}`` as default.
+
+Technicalities
+--------------
+
+- The catcode of the semi-colon is reset temporarily by `\\poldef
+ <poldef;_>`_ macro in case some other package (for example the French
+ babel module) may have made it active. This will fail though if the
+ whole thing was already part of a macro argument, in such cases one
+ can use `\\PolDef{f}{P(x)} <PolDef_>`_
+ rather. The colon in ``:=`` may be active with no consequences.
+
+- As a consequence of xintfrac_ addition and subtraction always using
+ least common multiples for the denominators [#]_, user-chosen common
+ denominators survive additions and multiplications. For example, this::
+
+ \poldef P(x):= 1/2 + 2/2*x + 3/2*x^3 + 4/2*x^4;
+ \poldef Q(x):= 1/3 + (2/3)x + (3/3)x^3 + (4/3)x^4;
+ \poldef PQ(x):= P(x)Q(x);
+
+ gives internally the polynomial::
+
+ 1/6+4/6*x^1+4/6*x^2+6/6*x^3+20/6*x^4+16/6*x^5+9/6*x^6+24/6*x^7+16/6*x^8
+
+ where all coefficients have the same denominator 6. Notice though that
+ ``\PolToExpr{PQ}`` outputs the ``6/6*x^3`` as ``x^3`` because (by
+ default) it recognizes and filters out coefficients equal to one or
+ minus one (since release ``0.3``). One can use for example
+ ``\PolToCSV{PQ}`` to see the internally stored coefficients.
+
+ .. [#] prior to ``0.4.1``, ``polexpr`` used to temporarily patch
+ during the parsing of polynomials the xintfrac_ macros. This
+ patch was backported to xint_ at release ``1.3``.
+
+- `\\PolDiff{polname_1}{polname_2}`_ always applies ``\xintIrr`` to the
+ resulting coefficients, except that the *power of ten* part ``[N]``
+ (for example an input in scientific notation such as ``1.23e5`` gives
+ ``123/1[3]`` internally in xintfrac) is not taken into account in the
+ reduction of the fraction. This is tentative and may change.
+
+ Same remark for `\\PolAntiDiff{polname_1}{polname_2}`_.
+
+- Currently, the package stores all coefficients from index ``0`` to
+ index equal to the polynomial degree inside a single macro, as a list.
+ This data structure is obviously very inefficient for polynomials of
+ high degree and few coefficients (as an example with ``\poldef
+ f(x):=x^1000 + x^500;`` the subsequent definition ``\poldef g(x):=
+ f(x)^2;`` will do of the order of 1,000,000 multiplications and
+ additions involvings only zeroes... which does take time). This
+ may change in the future.
+
+- As is to be expected internal structures of the package are barely
+ documented and unstable. Don't use them.
+
+
+CHANGE LOG
+----------
+
+- v0.1 (2018/01/11): initial release. Features:
+
+ * The `\\poldef <poldef;_>`_ parser itself,
+ * Differentiation and anti-differentiation,
+ * Euclidean division and GCDs,
+ * Various utilities such as `\\PolFromCSV <PolFromCSV_>`_,
+ `\\PolMapCoeffs <PolMapCoeffs_>`_,
+ `\\PolToCSV <PolToCSV_>`_, `\\PolToExpr <PolToExpr_>`_, ...
+
+ Only one-variable polynomials so far.
+
+- v0.2 (2018/01/14)
+
+ * Fix: ``"README thinks \numexpr recognizes ^ operator"``.
+ * Convert README to reStructuredText markup.
+ * Move main documentation from README to separate ``polexpr.txt`` file.
+ * Provide ``polexpr.html`` as obtained via DocUtils_ ``rst2html.py``.
+ * Convert README to (CTAN compatible) Markdown markup.
+
+ Due to lack of available time the test suite might not be extensive
+ enough. Bug reports are very welcome!
+
+- v0.3 (2018/01/17)
+
+ * bug fixes:
+
+ - the ``0.1`` `\\PolEval <PolEvalAt_>`_ accepted expressions for its second
+ argument, but this was removed by mistake at ``0.2``. Restored.
+
+ **Attention**: at ``0.4`` this has been reverted again, and
+ `\\PolEval{P}\\AtExpr{foo} <PolEvalAtExpr_>`_ syntax is needed for
+ using expressions in the second argument.
+ * incompatible or breaking changes:
+
+ - `\\PolToExpr <PolToExpr_>`_ now by default uses *descending*
+ powers (it also treats differently coefficients equal to 1 or -1.)
+ Use `\\PolToExpr* <PolToExpr*_>`_ for *ascending* powers.
+ - `\\PolEval <PolEvalAt_>`_ reduced the output to smallest terms,
+ but as this is costly with big fractions and not needed if e.g.
+ wrapped in an ``\xintRound`` or ``\xintFloat``, this step has been
+ removed; the former meaning is available as `\\PolEvalReduced
+ <PolEvalReducedAt_>`_.
+ * new (or newly documented) macros:
+
+ - `\\PolTypesetCmd <PolTypesetCmd_>`_
+ - `\\PolTypesetCmdPrefix <PolTypesetCmdPrefix_>`_
+ - `\\PolTypesetMonomialCmd <PolTypesetMonomialCmd_>`_
+ - `\\PolEvalReducedAt <PolEvalReducedAt_>`_
+ - `\\PolToFloatExpr <PolToFloatExpr_>`_
+ - `\\PolToExprOneTerm <PolToExprOneTerm_>`_
+ - `\\PolToFloatExprOneTerm <PolToFloatExprOneTerm_>`_
+ - `\\PolToExprCmd <PolToExprCmd_>`_
+ - `\\PolToFloatExprCmd <PolToFloatExprCmd_>`_
+ - `\\PolToExprTermPrefix <PolToExprTermPrefix_>`_
+ - `\\PolToExprVar <PolToExprVar_>`_
+ - `\\PolToExprTimes <PolToExprTimes_>`_
+ * improvements:
+
+ - documentation has a table of contents, internal hyperlinks,
+ standardized signature notations and added explanations.
+ - one can do ``\PolLet{g}={f}`` or ``\PolLet{g}{f}``.
+ - ``\PolToExpr{f}`` is highly customizable.
+ - `\\poldef <poldef;_>`_ and other defining macros prepare the polynomial
+ functions for usage within ``\xintthefloatexpr`` (or
+ ``\xintdeffloatvar``). Coefficients are pre-rounded to the
+ floating point precision. Indispensible for numerical algorithms,
+ as exact fractions, even reduced, quickly become very big. See the
+ documentation about how to use the exact polynomials also in
+ floating point context.
+
+ **Attention**: this has been reverted at ``0.4``. The macro
+ `\\PolGenFloatVariant <PolGenFloatVariant_>`_ must be used for
+ generation floating point polynomial functions.
+
+- v0.3.1 (2018/01/18)
+
+ Fixes two typos in example code included in the documentation.
+
+- v0.4 (2018/02/16)
+
+ * bug fixes:
+
+ - when Euclidean division gave a zero remainder, the internal
+ representation of this zero polynomial could be faulty; this
+ could cause mysterious bugs in conjunction with other package
+ macros such as `\\PolMapCoeffs <PolMapCoeffs_>`_.
+ - `\\PolGCD <PolGCD_>`_ was buggy in case of first polynomial being
+ of lesser degree than the second one.
+ * breaking changes:
+
+ - formerly `\\PolEval{P}\\At{foo} <PolEvalAt_>`_ allowed ``foo`` to
+ be an expression, which was transparently handled via
+ ``\xinttheexpr``. Now, ``foo`` must be a fraction (or a macro
+ expanding to such) in the format acceptable by ``xintfrac.sty``
+ macros. Use `\\PolEval{P}\\AtExpr{foo} <PolEvalAtExpr_>`_ for more
+ general arguments using expression syntax. E.g., if ``foo`` is the
+ name of a variable known to ``\xintexpr``.
+
+ The same holds for `\\PolEvalReduced <PolEvalReducedAt_>`_
+ and `\\PolFloatEval <PolFloatEvalAt_>`_.
+ - the ``3.0`` automatic generation of floating point variants has
+ been reverted. Not only do *not* the package macros automatically
+ generate floating point variants of newly created polynomials,
+ they actually make pre-existing such variant undefined.
+
+ See `\\PolGenFloatVariant <PolGenFloatVariant_>`_.
+ * new non-expandable macros:
+
+ - `\\PolGenFloatVariant <PolGenFloatVariant_>`_
+ - `\\PolGlobalLet <PolGlobalLet_>`_
+ - `\\PolTypesetOne <PolTypesetOne_>`_
+ - `\\PolQuo <PolQuo_>`_
+ - `\\PolRem <PolRem_>`_
+ - `\\PolToSturm <PolToSturm_>`_
+ - `\\PolToSturm\* <PolToSturm*_>`_
+ - `\\PolSetToSturmChainSignChangesAt <PolSetToSturmChainSignChangesAt_>`_
+ - `\\PolSetToNbOfZerosWithin <PolSetToNbOfZerosWithin_>`_
+ - `\\PolSturmIsolateZeros <PolSturmIsolateZeros_>`_
+ - `\\PolRefineInterval* <PolRefineInterval*_>`_
+ - `\\PolRefineInterval[N] <PolRefineInterval[N]_>`_
+ - `\\PolEnsureIntervalLength <PolEnsureIntervalLength_>`_
+ - `\\PolEnsureIntervalLengths <PolEnsureIntervalLengths_>`_
+ - `\\PolPrintIntervals <PolPrintIntervals_>`_
+ - `\\PolPrintIntervalsPrintExactZero <PolPrintIntervalsPrintExactZero_>`_
+ - `\\PolPrintIntervalsPrintLeftEndPoint <PolPrintIntervalsPrintLeftEndPoint_>`_
+ - `\\PolPrintIntervalsPrintRightEndPoint <PolPrintIntervalsPrintRightEndPoint_>`_
+ - `\\PolReduceCoeffs* <PolReduceCoeffs*_>`_
+ - `\\PolMakeMonic <PolMakeMonic_>`_
+ * new expandable macros:
+
+ - `\\PolToExprOneTermStyleA <PolToExprOneTermStyleA_>`_
+ - `\\PolIfCoeffIsPlusOrMinusOne <PolIfCoeffIsPlusOrMinusOne_>`_
+ - `\\PolLeadingCoeff <PolLeadingCoeff_>`_
+ - `\\PolSturmChainLength <PolSturmChainLength_>`_
+ - `\\PolSturmNbOfIsolatedZeros <PolSturmNbOfIsolatedZeros_>`_
+ - `\\PolSturmIfZeroExactlyKnown <PolSturmIfZeroExactlyKnown_>`_
+ - `\\PolSturmIsolatedZeroLeft <PolSturmIsolatedZeroLeft_>`_
+ - `\\PolSturmIsolatedZeroRight <PolSturmIsolatedZeroRight_>`_
+ - ``\PolPrintIntervalsTheEndPoint`` (removed at 0.7)
+ - `\\PolPrintIntervalsTheIndex`_
+ - ``\PolIfEndPointIsPositive`` (removed at 0.7)
+ - ``\PolIfEndPointIsNegative`` (removed at 0.7)
+ - ``\PolIfEndPointIsZero`` (removed at 0.7)
+ - `\\PolIntervalWidth <PolIntervalWidth_>`_
+ - `\\PolDecToString <PolDecToString_>`_
+ * improvements:
+
+ The main new feature is implementation of the `Sturm algorithm`_
+ for localization of the real roots of polynomials.
+
+- v0.4.1 (2018/03/01)
+
+ Synced with xint 1.3.
+
+- v0.4.2 (2018/03/03)
+
+ Documentation fix.
+
+- v0.5 (2018/04/08)
+
+ * bug fixes:
+
+ - `\\PolGet{polname}\\fromarray\\macro`_ crashed when ``\macro`` was
+ an xinttools_ array macro with no items. It now produces the zero
+ polynomial.
+ * breaking changes:
+
+ - `\\PolToSturm`_ creates primitive integer coefficients polynomials.
+ This speeds up localization of roots via
+ `\\PolSturmIsolateZeros`_. In case of user protests the author
+ will make available again the code producing the bona fide Sturm
+ polynomials as used formerly.
+ - polynomials created from `\\PolFromCSV`_ or `\\PolGet <PolGet_>`_
+ get their coefficients normalized via xintfrac_\ 's ``\xintRaw``.
+ * experimental change:
+
+ - optional argument to `\\PolSturmIsolateZeros`_ (see `The
+ degree 41 polynomial with -2, -1.9, -1.8, ..., 0, 0.1, ..., 1.9, 2
+ as roots`_ for usage). It will presumably be replaced in future by
+ an interval specification.
+ * new non-expandable macro:
+
+ - `\\PolMakePrimitive`_
+ * new expandable macro:
+
+ - `\\PolIContent`_
+
+- v0.5.1 (2018/04/22)
+
+ * new feature:
+
+ - the character ``'`` can be used in polynomial names.
+
+- v0.6 (2018/11/20)
+
+ * bugfix:
+
+ - the starred variant `\\PolToSturm*{polname}{sturmname}`_ was
+ broken. On the occasion of the fix, its meaning has been modified,
+ see its documentation.
+
+ - using `\\PolToSturm <PolToSturm_>`_ with a constant polynomial
+ caused a division by zero error.
+
+ * new macro:
+
+ - `\\PolSturmIsolateZeros* <PolSturmIsolateZeros*_>`_
+ acts like the `non-starred variant
+ <PolSturmIsolateZeros_>`_ then computes all the multiplicities.
+
+ * new expandable macros:
+
+ - `\\PolSturmIsolatedZeroMultiplicity{sturmname}{index}`_
+ - `\\PolSturmNbOfRootsOf{sturmname}\\LessThanOrEqualTo{value}`_
+ - `\\PolSturmNbOfRootsOf{sturmname}\\LessThanOrEqualToExpr{expression}`_
+ - `\\PolSturmNbWithMultOfRootsOf{sturmname}\\LessThanOrEqualTo{value}`_
+ - `\\PolSturmNbWithMultOfRootsOf{sturmname}\\LessThanOrEqualToExpr{expression}`_
+
+- v0.7 (2018/12/08), v0.7.1 (bugfix), v0.7.2 (2nd bugfix) (2018/12/09)
+
+ * breaking changes:
+
+ - although `\\PolPrintIntervals[varname]{sturmname}`_ default output
+ remains the same, some auxiliary macros for user-customization
+ have been removed: ``\PolPrintIntervalsTheEndPoint``,
+ ``\PolIfEndPointIsPositive{A}{B}``,
+ ``\PolIfEndPointIsNegative{A}{B}``, and
+ ``\PolIfEndPointIsZero{A}{B}``.
+
+ * bugfix:
+
+ - it could happen that, contrarily to documentation, an interval
+ computed by `\\PolSturmIsolateZeros{sturmname}`_ had zero as an
+ endpoint,
+ - `\\PolEnsureIntervalLength{sturmname}{index}{E}`_ could under
+ certain circumstances erroneously replace a non-zero root by
+ zero,
+ - `\\PolEnsureIntervalLengths{sturmname}{E}`_ crashed when used with
+ a polynomial with no real roots, hence for which no isolation intervals
+ existed (thanks to Thomas Söll for report).
+
+ * new macros:
+
+ - `\\PolSturmIsolateZeros**{sturmname}`_
+ - `\\PolSturmIsolateZerosGetMultiplicitiesAndRationalRoots{sturmname}`_
+ - `\\PolSturmIsolateZerosAndFindRationalRoots{sturmname}`_
+ - `\\polexprsetup`_
+ - `\\PolPrintIntervals* <PolPrintIntervals*_>`_
+ - `\\PolPrintIntervalsNoRealRoots`_
+ - `\\PolPrintIntervalsBeginEnv`_
+ - `\\PolPrintIntervalsEndEnv`_
+ - `\\PolPrintIntervalsKnownRoot`_
+ - `\\PolPrintIntervalsUnknownRoot`_
+ - `\\PolPrintIntervalsPrintMultiplicity`_
+
+ * new expandable macros:
+
+ - `\\PolSturmNbOfRationalRoots{sturmname}`_
+ - `\\PolSturmNbOfRationalRootsWithMultiplicities{sturmname}`_
+ - `\\PolSturmRationalRoot{sturmname}{k}`_
+ - `\\PolSturmRationalRootIndex{sturmname}{k}`_
+ - `\\PolSturmRationalRootMultiplicity{sturmname}{k}`_
+ - `\\PolPrintIntervalsTheVar`_
+ - `\\PolPrintIntervalsTheSturmName`_
+ - `\\PolPrintIntervalsTheMultiplicity`_
+
+- v0.7.3 (2019/02/04)
+
+ * bugfix:
+
+ - Debugging information not destined to user showed in log if root
+ finding was done under ``\xintverbosetrue`` regime.
+ - `\\PolPrintIntervalsTheVar`_ remained defined after
+ `\\PolPrintIntervals`_ but was left undefined after
+ `\\PolPrintIntervals*`_ (reported by Jürgen Gilg). Now remains
+ defined in both cases, and `\\PolPrintIntervalsTheSturmName`_
+ also.
+ - Polynomial names ending in digits caused errors (reported by Thomas
+ Söll).
+
+- v0.7.4 (2019/02/12)
+
+ * bugfix:
+
+ - 20000000000 is too big for ``\numexpr``, shouldn't I know that?
+ Thanks to Jürgen Gilg for report.
+
+Acknowledgments
+---------------
+
+Thanks to Jürgen Gilg whose question about xint_ usage for
+differentiating polynomials was the initial trigger leading to this
+package, and to Jürgen Gilg and Thomas Söll for testing it on some
+concrete problems.
+
+Renewed thanks to them on occasion of the ``0.6`` and ``0.7`` releases for their
+continued interest.
+
+See README.md for the License.
+
+.. _xinttools:
+.. _xintfrac:
+.. _xintexpr:
+.. _xint: http://www.ctan.org/pkg/xint
+
+.. _Wilkinson polynomial: https://en.wikipedia.org/wiki/Wilkinson%27s_polynomial
+
+.. _Sturm algorithm:
+.. _Sturm Theorem: https://en.wikipedia.org/wiki/Sturm%27s_theorem
+
+.. _DocUtils: http://docutils.sourceforge.net/docs/index.html