back to table · edit · history · where entries came from · files · download
4283 bytes, as of the version from 2026-10-26 12:11. Recorded here, not run.
"""Values of the Scorer function Gi -- numberdb.org/T514.
Run with SageMath:
sage -pip install numberdb
sage -python generate.py # verify all stored entries (key for draft)
sage -python checks.py # independent checks; no key needed
sage -python generate.py --fill # fill the draft, NUMBERDB_API_KEY required
The nine rational arguments and their ordering follow family #211. The
normalization is DLMF 9.12.19: Gi''(x) - x Gi(x) = -1/pi. No scaling is applied.
All arithmetic uses Arb balls. Coefficients c_0 and c_1 are DLMF 9.12.6-7,
c_2 = -1/(2*pi), and c_(k+3) = c_k/((k+3)*(k+2)). For each residue class
modulo 3, after the term c_k*x^k has been added, put
q = |x|^3/((k+3)*(k+2)). Once q < 1, every later ratio is <= q, so the
omitted absolute tail is <= |c_k*x^k|*q/(1-q). Each tail is explicitly
added as a symmetric error ball, not merely used as a stopping criterion.
At digits=100 the field has 665 bits (roughly 200 decimal digits), and
each of the three tails is below 10^-150. This deliberately separates
rounding error from truncation error. The checks measure the final ball
accuracy and refuse any enclosure with fewer than 110 decimal digits.
The table writes 100 significant digits, with the last place uncertain by
one as specified by NumberDB. The constants here are not tuned per entry.
"""
import os
import sys
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
ARGUMENTS = ('0', '1/2', '-1/2', '1', '-1', '2', '-2', '10', '-10')
WORKING_GUARD_BITS = 332
TAIL_GUARD_DIGITS = 50
def scorer_gi(x, digits=100, diagnostics=False):
x = QQ(x)
field = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD_BITS))
z = field(x)
pi = field.pi()
initial = (
1 / (field(3)**(QQ(7)/6) * field(QQ(2)/3).gamma()),
1 / (field(3)**(QQ(5)/6) * field(QQ(1)/3).gamma()),
-1 / (2*pi),
)
tolerance = field(10)**(-digits-TAIL_GUARD_DIGITS)
answer = field(0)
tails = []
last_indices = []
for r, coefficient in enumerate(initial):
term = coefficient * z**r
k = r
subtotal = field(0)
while True:
subtotal += term
ratio = field(abs(x)**3) / ((k+3)*(k+2))
if ratio < 1:
tail = abs(term)*ratio/(1-ratio)
if tail < tolerance:
subtotal = subtotal.add_error(tail)
tails.append(tail)
last_indices.append(k)
break
term = term*z**3/((k+3)*(k+2))
k += 3
if k > 100000:
raise ArithmeticError('Taylor series did not reach its tail target')
answer += subtotal
assert answer.is_finite()
assert answer.accuracy() >= numberdb.bits(digits+10, losing=0)
if diagnostics:
return answer, {'last_indices': last_indices,
'tail_bounds': [str(t) for t in tails],
'accuracy_bits': int(answer.accuracy()),
'field_bits': int(field.precision())}
return answer
class ScorerGiValues(numberdb.Generator):
table = 'T514'
parameters = ('x',)
type = 'R'
digits = 100
rigour = 'proven'
files = ('generate.py', 'checks.py', 'check.py', 'dry_run.py', 'run_dry.py',
'checks-evidence.json', 'dry-run.log')
def enumerate(self):
for x in ARGUMENTS:
yield {'x': x}
def value(self, params, digits):
value = scorer_gi(params['x'], digits)
if QQ(params['x']) == 0:
return {'number': value,
'comment': r'At the origin, $\operatorname{Gi}(0)=1/(3^{7/6}\Gamma(2/3))$.'}
return value
if __name__ == '__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
os.environ['NUMBERDB_API_KEY'] = sys.stdin.read().strip()
generator = ScorerGiValues()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
print(generator.publish(message='Fill nine Gi values with rigorous Taylor enclosures and independent checks'))
else:
report = generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)