simon-git: spigot (master): Simon Tatham
Commits to Tartarus hosted VCS
tartarus-commits at lists.tartarus.org
Sun Mar 18 23:11:44 GMT 2018
TL;DR:
5be7408 C++ cleanup: replace more constructors with "= default".
c6a6649 Separate spigot_error into several subclasses.
94e25a6 Implement the generalised hypergeometric function.
82e0799 Implement the arithmetic-geometric mean.
c92b025 Implement Gauss's constant.
a789f73 Fast computation of pi^2/6.
1b3d018 Fix cut-and-paste error in Enforcer.
d8b8ade Implement the dilogarithm, aka Spence's function, aka Li2.
22ef0e5 Implement Bessel J functions, of integer order.
17c4cea Improve description of zeta in Python docs.
Repository: https://git.tartarus.org/simon/spigot.git
On the web: https://git.tartarus.org/?p=simon/spigot.git
Branch updated: master
Committer: Simon Tatham <anakin at pobox.com>
Date: 2018-03-18 23:11:43
commit 5be7408ed4e0db5152ff7765c7511d483027d38b
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=5be7408ed4e0db5152ff7765c7511d483027d38b;hp=cbe612704fed81e6223fcce76fa6838c4a14ff62
Author: Simon Tatham <anakin at pobox.com>
Date: Thu Mar 15 19:27:06 2018 +0000
C++ cleanup: replace more constructors with "= default".
I wonder if there's a C++03 -> C++11 refactoring tool that will give
me a complete list of these tedious boilerplate functions that can
safely be replaced with an "= default".
error.cpp | 15 ---------------
error.h | 6 +++---
2 files changed, 3 insertions(+), 18 deletions(-)
commit c6a66492ff1167ec7f46fed3b2d5cbbcd6393523
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=c6a66492ff1167ec7f46fed3b2d5cbbcd6393523;hp=5be7408ed4e0db5152ff7765c7511d483027d38b
Author: Simon Tatham <anakin at pobox.com>
Date: Thu Mar 15 19:32:12 2018 +0000
Separate spigot_error into several subclasses.
NFCI, but this should now allow me to selectively catch the different
subtypes of expression.
In particular, I had the idea that classes like MonotoneHelper, which
repeatedly evaluate some other function for different input values,
might want to catch a domain error in one of those sub-evaluations and
handle it in a way that's non-fatal to the overall goal (e.g. just
wait for a value closer to the real input and hope that one doesn't
have the same problem). In that situation, I wouldn't want the same
catch-and-retry clause to sweep up fundamental setup mistakes that
have nothing to do with the particular choice of input value; those
should be passed back to main() (or to Python) the same as always.
I don't actually have a use case for this yet. I thought a new
function I was working on was going to need it, but it turned out not
to. But I think this is a positive change anyway, so now I've gone to
the effort of writing it, I'll keep it.
algebraic.cpp | 10 ++--
arithmetic.cpp | 4 +-
baseout.cpp | 2 +-
cfracout.cpp | 6 +--
enforce.cpp | 8 +--
error.cpp | 2 +-
error.h | 94 +++++++++++++++++++++++++++++++---
exp.cpp | 30 +++++------
expint.cpp | 14 ++---
expr.cpp | 124 ++++++++++++++++++++++-----------------------
gamma.cpp | 2 +-
io.cpp | 4 +-
iocli.cpp | 10 ++--
lambertw.cpp | 10 ++--
main.cpp | 8 +--
python-module/internal.cpp | 37 ++++++--------
sqrt.cpp | 10 ++--
trig.cpp | 4 +-
trigint.cpp | 2 +-
unary.cpp | 2 +-
20 files changed, 230 insertions(+), 153 deletions(-)
commit 94e25a637d38553e98e5cd8de01779a9e35b3a46
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=94e25a637d38553e98e5cd8de01779a9e35b3a46;hp=c6a66492ff1167ec7f46fed3b2d5cbbcd6393523
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Mar 18 19:33:52 2018 +0000
Implement the generalised hypergeometric function.
This isn't currently exposed in any user-visible function; it's just
groundwork which will be used by several functions I'm about to add.
The hardest thing about implementing a primitive for a function type
this general turned out to be judging the size of the starting
interval to ensure each matrix is refining. It's starting to make me
think I should actually get round to the chore that's been on my TODO
list for ages, of putting a check somewhere centralised to ensure all
the matrices that ought to be refining their starting interval really
do.
hypergeom.cpp | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
sources.mk | 2 +-
2 files changed, 289 insertions(+), 1 deletion(-)
commit 82e0799aefe24a8f0b31618829e366f63e6f123a
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=82e0799aefe24a8f0b31618829e366f63e6f123a;hp=94e25a637d38553e98e5cd8de01779a9e35b3a46
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Mar 18 19:36:11 2018 +0000
Implement the arithmetic-geometric mean.
This is an amusingly backwards way to go about things. All my reading
suggests that the AGM is more often useful because of the very fast
convergence of the obvious iteration for computing it than because of
the usefulness of the actual function it implements - AGM methods are
used to compute other functions like elliptic integrals. Whereas here,
the AGM iteration - fast as it may be - is thoroughly unsuited to
spigot's constraints, so I'm implementing the AGM function by a means
that _isn't_ the ordinary AGM iteration. Specifically, relating the
AGM to an elliptic integral and then relating elliptic integrals to
the hypergeometric function, we get a way to compute the AGM by a
series that only converges like an ordinary geometric series and not
with any accelerating quadratic awesomeness.
This was also a tricky function to implement because of the initial
conditions: you want agm(0,anything) to come out as 0, which means
that agm(non-obvious zero, anything) has to _converge_ to 0 even if
the other argument isn't zero. The solution to that was a prefix
wrapper class similar to the one I used for pow, which narrows its
output interval around zero as much as it can until (unless) both
inputs become bounded away from zero, and then switches over to the
underlying hypergeometric-based AGM implementation.
(The narrowing is pretty slow, though, if you do try to compute agm of
a non-obvious zero and a nonzero constant, e.g. agm(pi-pi,1). It looks
as if an intuitive visualisation of the AGM for widely separated
numbers 0<a<b is that, if agm(a,b) is n orders of magnitude larger
than a, it's log n orders smaller than b. That means that in order to
prove agm(a,1) is k orders smaller than 1, you need to prove that a is
c^k orders smaller than 1 (for some constant c I haven't bothered to
work out). So my tentative-output test which checks that the interval
_does_ narrow gradually about 0 in this circumstance has to run with
--tentative-test set to 4 digits rather than my usual default of 40.)
expr.cpp | 1 +
funcs.h | 3 +
hypergeom.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++++++
manpage.but | 4 +
manual.but | 7 ++
python-doc/api.rst | 7 ++
python-module/__init__.py | 14 ++++
python-module/testsuite | 1 +
test.sh | 9 +++
9 files changed, 248 insertions(+)
commit c92b0253818552ab65acd67963535e98a983a339
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=c92b0253818552ab65acd67963535e98a983a339;hp=82e0799aefe24a8f0b31618829e366f63e6f123a
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Mar 18 23:00:03 2018 +0000
Implement Gauss's constant.
Given the AGM, this isn't hard, because Gauss's constant is just
1/agm(1,sqrt(2)). In fact it's slightly easier than AGM, because
implementing AGM in terms of the hypergeometric function requires
squaring the input to the latter - and squaring sqrt(2), of course,
makes it rational again, so Gauss can be implemented via a direct call
to the underlying HgRational class without needing any of the
complicated machinery layered on top of that.
expr.cpp | 1 +
funcs.h | 1 +
hypergeom.cpp | 16 ++++++++++++++++
manpage.but | 4 ++++
manual.but | 2 ++
python-module/testsuite | 1 +
test.sh | 1 +
7 files changed, 26 insertions(+)
commit a789f73d39791038bfd57795b7a977d6bd784d5d
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=a789f73d39791038bfd57795b7a977d6bd784d5d;hp=c92b0253818552ab65acd67963535e98a983a339
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Mar 18 19:05:24 2018 +0000
Fast computation of pi^2/6.
I'm about to need it as a special value in a HoleFiller subclass, and
it struck me that since it comes up so often in other contexts (e.g.
zeta(2)) there was quite likely to be a formula for computing it
_faster_ than pi itself. And indeed, I found a continued fraction for
pi^2/6 (and any other rational multiple of pi^2 just as easily) that
spigot can compute about twice as fast as it could have done by
computing pi and squaring it.
(This also suggests that it would be nice to implement a tree
optimisation pass - if the user _asks_ for pi^2, you'd surely like to
switch over to this class! But if I were ever to head in that
direction, I'd want to do it with a great deal more thoroughness - not
to mention making sure there's a way to turn it off so that all the
current regression tests don't suddenly stop testing anything remotely
related to what they were originally supposed to test...)
consts.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
funcs.h | 1 +
2 files changed, 77 insertions(+)
commit 1b3d018bfa1be2c68ac38e5dca6b1335f1ae09be
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=1b3d018bfa1be2c68ac38e5dca6b1335f1ae09be;hp=a789f73d39791038bfd57795b7a977d6bd784d5d
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Mar 18 21:13:28 2018 +0000
Fix cut-and-paste error in Enforcer.
The clause for ENFORCE_LE / ENFORCE_LT apparently hasn't been tested
before, because it was absentmindedly comparing the wrong ends of the
two intervals against each other. Interval A is to the right of B if
A's _lower_ bound exceeds B's _upper_ bound, so to check that that
isn't the case, we have to check A_lo <= B_hi, not A_hi <= B_lo.
enforce.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
commit d8b8adeed0bf346d60fd96278afaaff5b426a96d
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=d8b8adeed0bf346d60fd96278afaaff5b426a96d;hp=1b3d018bfa1be2c68ac38e5dca6b1335f1ae09be
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Mar 18 23:03:46 2018 +0000
Implement the dilogarithm, aka Spence's function, aka Li2.
This was quite an involved piece of work, despite being 'just' another
exercise of the hypergeometric primitive. Li2 needs range reduction
via several different identities, using a carefully approximate method
of identifying the boundaries between the regions in which each one is
useful; it's not defined for x>1, so it needed an Enforcer; it takes a
special value _at_ x=1 which can't be computed by the same algorithm
as the values near 1, so it also needed a HoleFiller; and its
derivative goes infinite at the special point, which means that for
the first time I've had an opportunity to use the overridable
combine() method that I put in HoleFiller in 2015 anticipating that
sooner or later a situation like this would come up.
(Not to mention that the special value at x=1 is also pi^2/6 which I
just wrote an extra-fast generator for, and that this is the first use
in the code base of ENFORCE_LE in which I therefore naturally had to
fix a bug!)
expr.cpp | 1 +
funcs.h | 1 +
hypergeom.cpp | 142 ++++++++++++++++++++++++++++++++++++++++++++++
manpage.but | 4 ++
manual.but | 4 ++
python-doc/api.rst | 2 +
python-module/__init__.py | 7 +++
python-module/testsuite | 1 +
test.sh | 14 +++++
9 files changed, 176 insertions(+)
commit 22ef0e5f82bc326014683cf59cc67b7ad161e697
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=22ef0e5f82bc326014683cf59cc67b7ad161e697;hp=d8b8adeed0bf346d60fd96278afaaff5b426a96d
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Mar 18 23:06:06 2018 +0000
Implement Bessel J functions, of integer order.
These are yet another thing you can do with a hypergeometric
primitive.
They required a HoleFiller for the special value at 0, but it was only
a normal kind of HoleFiller, with none of the extra-special technical
wizardry needed by the dilogarithm.
The biggest problem here was that you want to use a MonotoneHelper,
but the Bessel functions _aren't_ monotonic - they oscillate up and
down for ever. So I had to use the same trick as in the trig
integrals, in which the constructor class provided to MonotoneHelper
evaluates f(x)+x instead of just f(x), and then after we get a result
back out of spigot_monotone, we can subtract x from it again.
(This technique works provided there's _some_ easy-to-calculate
monotonic function g such that |f'|<|g'| always, so that f+g is
monotonic. In this case - and also in the case of the trig integrals
where I last used this trick - all the functions in question are
Lipschitz with constant 1, so g(x)=x is such a function.)
expr.cpp | 1 +
funcs.h | 2 +
hypergeom.cpp | 138 ++++++++++++++++++++++++++++++++++++++++++++++
manpage.but | 6 +-
manual.but | 6 ++
python-doc/api.rst | 2 +
python-module/__init__.py | 20 +++++++
python-module/testsuite | 1 +
test.sh | 45 +++++++++++++++
9 files changed, 220 insertions(+), 1 deletion(-)
commit 17c4cea8616fee0673c164db5ef67f0149959437
web diff https://git.tartarus.org/?p=simon/spigot.git;a=commitdiff;h=17c4cea8616fee0673c164db5ef67f0149959437;hp=22ef0e5f82bc326014683cf59cc67b7ad161e697
Author: Simon Tatham <anakin at pobox.com>
Date: Sun Mar 18 21:25:49 2018 +0000
Improve description of zeta in Python docs.
This is a missing piece of commit d92301d23, which applied the same
re-wording in the main spigot manual and the comments. But I briefly
forgot that Python existed.
python-module/__init__.py | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
More information about the tartarus-commits
mailing list