Skip to content

Commit f6be461

Browse files
committed
several fixes
1 parent f5a5c46 commit f6be461

1 file changed

Lines changed: 50 additions & 35 deletions

File tree

mathics/builtin/constants.py

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
Symbol,
2020
strip_context,
2121
)
22-
from mathics.core.numbers import get_precision, PrecisionValueError
22+
from mathics.core.numbers import get_precision, PrecisionValueError, machine_precision
2323

2424

2525
def mp_constant(fn: str, d=None) -> mpmath.ctx_mp_python.mpf:
@@ -33,7 +33,7 @@ def mp_constant(fn: str, d=None) -> mpmath.ctx_mp_python.mpf:
3333
# ask for a certain number of digits, but the
3434
# accuracy will be less than that. Figure out
3535
# what's up and compensate somehow.
36-
mpmath.mp.dps = int_d = int(d)
36+
mpmath.mp.dps = int_d = int(d * 3.321928)
3737
return getattr(mpmath, fn)(prec=int_d)
3838

3939

@@ -47,10 +47,16 @@ def mp_convert_constant(obj, **kwargs):
4747

4848

4949
def numpy_constant(name: str, d=None) -> float:
50-
# TODO: although numpy doesn't support arbitrary precision,
51-
# if d is smaller than the precision given we could *reduce* the
52-
# float returned.
53-
return getattr(numpy, name)
50+
if d:
51+
# by mmatera: Here I have a question:
52+
# 0.0123`2 should be rounded to
53+
# 0.01 or to 0.0123?
54+
# (absolute versus relative accuracy)
55+
val = getattr(numpy, name)
56+
val = numpy.round(val, d)
57+
return val
58+
else:
59+
return getattr(numpy, name)
5460

5561

5662
def sympy_constant(fn, d=None):
@@ -61,13 +67,16 @@ class _Constant_Common(Predefined):
6167

6268
attributes = ("Constant", "Protected", "ReadProtected")
6369
nargs = 0
64-
options = {"Method": "sympy"}
70+
options = {"Method": "Automatic"}
6571

6672
def apply_N(self, precision, evaluation, options={}):
6773
"N[%(name)s, precision_?NumericQ, OptionsPattern[%(name)s]]"
6874

6975
preference = self.get_option(options, "Method", evaluation).get_string_value()
70-
return self.get_constant(precision, evaluation, preference)
76+
if preference == "Automatic":
77+
return self.get_constant(precision, evaluation)
78+
else:
79+
return self.get_constant(precision, evaluation, preference)
7180

7281
def apply_N2(self, evaluation, options={}):
7382
"N[%(name)s, OptionsPattern[%(name)s]]"
@@ -77,41 +86,47 @@ def is_constant(self) -> bool:
7786
return True
7887

7988
def get_constant(self, precision, evaluation, preference=None):
80-
## print("XXX", self, preference)
81-
if preference is None:
82-
preference = (
83-
evaluation.parse("Settings`$PreferredBackendMethod")
84-
.evaluate(evaluation)
85-
.get_string_value()
86-
)
87-
# TODO: validate PreferredBackendMethod is in "mpmath", "numpy", "sympy"
89+
# first, determine the precision
90+
machine_d = int( 0.30103 * machine_precision)
8891
d = None
8992
if precision:
9093
try:
9194
d = get_precision(precision, evaluation)
9295
except PrecisionValueError:
9396
pass
9497

95-
conversion_fn = MachineReal if d is None else PrecisionReal
96-
97-
# print("XXX1", self, preference, conversion_fn)
98-
99-
if preference == "sympy" and hasattr(self, "sympy_name"):
100-
value = sympy_constant(self.sympy_name, d)
101-
elif preference == "mpmath" and hasattr(self, "mpmath_name"):
102-
value = mp_constant(self.mpmath_name, d)
103-
elif preference == "numpy" and hasattr(self, "numpy_name"):
104-
# Note numpy doesn't support arbitarary precision
105-
value = numpy_constant(self.numpy_name, d)
106-
elif hasattr(self, "mpmath_name"):
107-
value = mp_constant(self.mpmath_name, d)
108-
elif hasattr(self, "sympy_name"):
109-
value = sympy_constant(self.sympy_name, d)
110-
elif hasattr(self, "numpy_name"):
111-
# Note numpy doesn't support arbitarary precision
112-
value = numpy_constant(self.numpy_name, d)
113-
return conversion_fn(value)
98+
if d is None:
99+
d = machine_d
114100

101+
# If preference not especified, determine it
102+
# from the precision.
103+
if preference is None:
104+
if d <= machine_d:
105+
preference = "numpy"
106+
else:
107+
preference = "mpmath"
108+
# If preference is not valid, send a message and return.
109+
if not (preference in ("sympy", "numpy", "mpmath")):
110+
evaluation.message(f'{preference} not in ("sympy", "numpy", "mpmath")')
111+
return
112+
# Try to determine the numeric value
113+
value = None
114+
if preference == "numpy":
115+
if hasattr(self, "numpy_name"):
116+
value = numpy_constant(self.numpy_name)
117+
if d == machine_d:
118+
return MachineReal(value)
119+
elif preference == "sympy":
120+
if hasattr(self, "sympy_name"):
121+
value = sympy_constant(self.sympy_name, d)
122+
elif preference == "mpmath":
123+
if hasattr(self, "sympy_name"):
124+
value = mp_constant(self.mpmath_name, d)
125+
if value:
126+
return PrecisionReal(sympy.Float(str(value), d))
127+
# If the value is not available, return none
128+
# and keep it unevaluated.
129+
return
115130

116131
class MPMathConstant(_Constant_Common):
117132
"""Representation of a constant in mpmath, e.g. Pi, E, I, etc."""

0 commit comments

Comments
 (0)