On Wed, Feb 27, 2013 at 7:28 PM, G B <g.c.b.at.w...@gmail.com> wrote: >> Why not just convert each arg to Float and use %, and leave the details up >> to Float.__mod__. > > In all honesty, because I have very little idea what I'm doing... =) > > > I just tried this, but it failed: > def _eval_evalf(self,prec): > args=[Float(x,prec) for x in self.args] > return N(args[0] % args[1],prec) > > > I put the traceback at the bottom of my message to avoid clutter... > > > >>I may not be clear what you're saying, but _eval_evalf only takes two >>arguments, self and prec. So where would subs be passed to? > > > Sorry, I should have been more clear. > > > As I read the code in EvalfMixin.evalf, it first tries to call > evalf(self,prec+4,options). I believe this evalf is in the evalf.py source > file itself. This version uses evalf_table for dispatch, rather than relying > on self to have its own implementation. One of the fields of 'options' is > the subs parameter passed to EvalfMixin.evalf > > > If this version of evalf raises NotImplementedError, then EvalfMixin.evalf > tries to call self._eval_evalf(prec). It doesn't try to pass the options > parameter to the _eval_evalf implemented in self, and therefore can't carry > the subs parameter passed to the EvalfMixin.evalf(self,n,subs,...) call. > > > I don't know the reason for the different calling conventions. It appears > like the dispatch table would best handle classes that can't be extended > with _eval_evalf, while leaving each class responsible for it's own > implementation otherwise. The options seem equally useful to both > implementation routes. I'm guessing this was an oversight, but I don't know > the history.
Oh I see. Probably it was an oversight. Aaron Meurer > > > Cheers-- > Greg > > > Here's that traceback: > ------------------------------------------------------------------- > 100 def _eval_evalf(self,prec): > --> 101 args=[Float(x,prec) for x in self.args] > 102 return N(args[0] % args[1],prec) > 103 # return N(mpmath.fmod(*[N(x,prec) for x in self.args]),prec) > > /Library/Python/2.7/site-packages/sympy/core/numbers.pyc in __new__(cls, > num, prec) > 589 _mpf_ = mpf_norm(_mpf_, prec) > 590 else: > --> 591 _mpf_ = mpmath.mpf(num)._mpf_ > 592 > 593 if not num: > > /Library/Python/2.7/site-packages/sympy/mpmath/ctx_mp_python.pyc in > __new__(cls, val, **kwargs) > 75 else: > 76 v = new(cls) > ---> 77 v._mpf_ = mpf_pos(cls.mpf_convert_arg(val, prec, > rounding), prec, rounding) > 78 return v > 79 > > /Library/Python/2.7/site-packages/sympy/mpmath/ctx_mp_python.pyc in > mpf_convert_arg(cls, x, prec, rounding) > 94 return a > 95 raise ValueError("can only create mpf from zero-width > interval") > ---> 96 raise TypeError("cannot create mpf from " + repr(x)) > 97 > 98 @classmethod > > TypeError: cannot create mpf from acos(cos(39*pi/115))/(2*pi) > > > > > > > > On Wednesday, February 27, 2013 4:55:46 PM UTC-8, Aaron Meurer wrote: >> >> On Wed, Feb 27, 2013 at 5:46 PM, G B <g.c.b....@gmail.com> wrote: >> > I'm not sure it matters in the end, but it looks like >> > Mod(Rational(15,7),1).n() works ok too. I think what's happening is >> > that >> > when pi isn't in the argument list, it basically gets simplified when >> > the >> > class construction calls Mod.eval but Mod.eval doesn't know how to >> > simplify >> > with pi. >> > >> > I've patched this into my Mod class: >> > >> > def _eval_evalf(self,prec): >> > return N(mpmath.fmod(*[N(x,prec) for x in self.args]),prec) >> >> You're passing SymPy Floats to the mpmath function, which is not >> really correct (though I guess it works). Why not just convert each >> arg to Float and use %, and leave the details up to Float.__mod__. >> >> > >> > It solves my immediate problem, but given how complex the evalf >> > functions >> > are for everything else, I get the feeling I've done something horribly, >> > inexcusably naive here. Am I missing anything? >> > >> > I tried Chris' examples and Mod(1e-40,1) returns 0 with my method even >> > though mpmath.fmod(1e-40,1) returns 1e-40. It also returns zero if I >> > write >> > it as Mod(Float(1e-40),S(1)). I get the proper results with >> > Mod(1e-40,1,evaluate=False).n(). >> > >> > Again, the problem appears to be in Mod.eval, but I'm not sure where. >> > >> > The other thing I noticed going through EvalfMixin.evalf is that the >> > options >> > parameter isn't passed to self._eval_evalf, which means that subs >> > parameters >> > won't get passed unless _eval_evalf is in the evalf_table. I don't know >> > if >> > this was intentional or an oversight. >> >> I may not be clear what you're saying, but _eval_evalf only takes two >> arguments, self and prec. So where would subs be passed to? >> >> Aaron Meurer >> >> > >> > Cheers-- >> > Greg >> > >> > >> > >> > On Wednesday, February 27, 2013 3:40:57 PM UTC-8, Aaron Meurer wrote: >> >> >> >> On Wed, Feb 27, 2013 at 1:41 PM, Chris Smith <smi...@gmail.com> wrote: >> >> >> It looks like Mod doesn't implement evalf at all, and it doesn't >> >> >> work >> >> >> automatically (that only happens if the function name is the same as >> >> >> the mpmath function name). It should be easy. Just evaluate the >> >> >> arguments, and then take the mod of them. >> >> > >> >> > In general this is not going to work: >> >> > >> >> > ``` >> >> >>>> Mod(1e-30,3) >> >> > 1.00000000000000e-30 >> >> >>>> Mod(1e-40,3) >> >> > 0.0 >> >> > ``` >> >> > >> >> > whereas >> >> > >> >> > ``` >> >> >>>> 1e-40 % 3 >> >> > 9.9999999999999993e-41 >> >> > ``` >> >> >> >> Isn't that just a roundoff error. If you use Float, you get 1e-40. >> >> >> >> Aaron Meurer >> >> >> >> > >> >> > Something like this might work when a > b (when a < b the answer is >> >> > `a`): >> >> > >> >> > ``` >> >> >>>> a,b=pi**3,S(3) >> >> >>>> (a - round(a/b)*b).n() >> >> > 1.00627668029982 >> >> >>>> a.n() % b.n() >> >> > 1.00627668029982 >> >> > ``` >> >> > >> >> > -- >> >> > You received this message because you are subscribed to the Google >> >> > Groups "sympy" group. >> >> > To unsubscribe from this group and stop receiving emails from it, >> >> > send >> >> > an email to sympy+un...@googlegroups.com. >> >> > To post to this group, send email to sy...@googlegroups.com. >> >> > Visit this group at http://groups.google.com/group/sympy?hl=en. >> >> > For more options, visit https://groups.google.com/groups/opt_out. >> >> > >> >> > >> > >> > -- >> > You received this message because you are subscribed to the Google >> > Groups >> > "sympy" group. >> > To unsubscribe from this group and stop receiving emails from it, send >> > an >> > email to sympy+un...@googlegroups.com. >> > To post to this group, send email to sy...@googlegroups.com. >> > Visit this group at http://groups.google.com/group/sympy?hl=en. >> > For more options, visit https://groups.google.com/groups/opt_out. >> > >> > > > -- > You received this message because you are subscribed to the Google Groups > "sympy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sympy+unsubscr...@googlegroups.com. > To post to this group, send email to sympy@googlegroups.com. > Visit this group at http://groups.google.com/group/sympy?hl=en. > For more options, visit https://groups.google.com/groups/opt_out. > > -- You received this message because you are subscribed to the Google Groups "sympy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sympy+unsubscr...@googlegroups.com. To post to this group, send email to sympy@googlegroups.com. Visit this group at http://groups.google.com/group/sympy?hl=en. For more options, visit https://groups.google.com/groups/opt_out.