Hi, I think the current way of representing Floats is reasonable.
Float internally keeps it in binary representation, so any non-terminating number in base 2 is truncated when stored as a Float. That's why there is a string constructor which can take in an exact decimal value and create a number in binary representation with precision mentioned. Note that in this way only numbers representable as a sum of different powers of two have an exact value. Others can also be represented in an exact form if the base of the float is different than 2, but I think mpmath and many other libraries use only base 2. If you want an exact form, best way would be to define it as a Rational and then you can do 1/3 as well which you can't if it's in decimal form. One other good thing about Rational is that `sin(Rational)` won't be evaluated unless SymPy knows the exact value, whereas `sin(Float)` would evaluate leading to error propagation even if it's something like `0.5` which represented exactly in binary representation. Isuru Fernando On Tue, Apr 5, 2016 at 10:38 PM, Aaron Meurer <[email protected]> wrote: > On Tue, Apr 5, 2016 at 12:54 PM, Oscar Benjamin > <[email protected]> wrote: > > On 5 April 2016 at 17:15, Aaron Meurer <[email protected]> wrote: > >> On Tue, Apr 5, 2016 at 6:19 AM, Oscar Benjamin > >> <[email protected]> wrote: > >>> > >>> I though that it should be possible to easily do this with sympy > >>> Floats but it doesn't seem to work: > >>> > >>> In [1]: x = S(1.4142) > >>> > >>> In [2]: x > >>> Out[2]: 1.41420000000000 > >>> > >>> In [3]: x**6000 > >>> Out[3]: 1.16144178843571e+903 > >>> > >>> In [4]: x**6000 % 400 > >>> Out[4]: 32.0000000000000 > >>> > >>> This doesn't work because auto-evaluation of x**6000 destroyed all the > >>> precision so I tried: > >> > >> No, it's because the default precision is 15. I didn't realize you > >> needed a precision of 950. If you do what I did above with that you > >> get the right answer > >> > >> In [6]: x = Float("1.4142", 950) > > ... > > > > It is because of the auto-evaluation in the sense that there were > > enough digits to exactly represent all the input numbers but the > > auto-evaluation cheated me from specifying how many digits to use for > > the exponentiation with evalf later. I think that inexact > > auto-evaluation should be disabled by default. Explicitly calling > > .evalf() serves as a useful reminder of the numeric approximations > > that have occurred in the calculation and should be required for this. > > > >>> So let's disable evaluation of at the mod step as well: > >>> > >>> In [10]: Mod(Pow(x, 6000, evaluate=False), 400, > evaluate=False).evalf(50) > >>> Out[10]: > >>> ⎛ 6000 ⎞ > >>> Mod⎝1.4142 , 400⎠ > >>> > >>> How do I get that to actually evaluate? > >> > >> expr.doit() will evaluate the expression, but it evaluates it using > >> the prevision of x. For your x, that's 15, so you get the wrong answer > >> 32. If you set x = Float("1.4142", 950) you get the right answer. > > > > Is there a reason for not evaluating this when evalf is called? > > No, that's also a bug. Unevaluated objects in SymPy tend to be pretty > buggy. > > > > > ... > >> > >> I don't know if it should be considered a bug, but it's worth noting > >> that if you want SymPy to give the right precision in general you have > >> to start with Float objects that are set with the precision you need. > >> To me it feels like a bug because it negates the purpose of the evalf > >> precision argument. > > > > Is there a coherent policy on float-handling in sympy? > > > > My ideal would be: > > > > 1) All float objects are created exact (having the exact value of the > > object passed in). > > 2) No inexact auto-evaluation. > > 3) .evalf() can be used to fully evaluate the expression with desired > precision. > > 4) Ideally the precision argument to .evalf would be the precision of > > the *output* rather than the internal precision of the intermediate > > calculations > > Can you clarify what you mean by "exact" here? > > Note that there's no way to know what the input value of a float is. > That is, there's no way to write Float(0.2) (with no quotes) and have > it be treated as Float(2/10). The 0.2 object is converted to a Python > floating point by the time that Float sees it, and it's not a decimal: > > In [49]: (0.2).as_integer_ratio() > Out[49]: (3602879701896397, 18014398509481984) > > That's why Float allows string input (and it's the recommended way of > creating them). > > With that being said, I don't think the fact that > (1.4142).as_integer_ratio() isn't (7071, 5000) is the problem here. > Float(1.4142) is indeed inexact compared to Float('1.4142'), but the > wrong answers from x**6000%400 come from lack of computing precision, > not lack of input accuracy. > > > > > Currently 1) already occurs for decimal strings but Float(float) > > rounds to 15 digits and you can explicitly force something impossible > > as a ratio string: Float("1/3"). I think Float should be more like > > decimal.Decimal here: all input arguments are treated as exact > > regardless of precision etc. (and I don't see any good reason for > > allowing Float("1/3")) > > > > Without 2) it is impossible to achieve 3). If approximate > > auto-evaluation can occur before calling .evalf then there's no way > > for evalf to set the precision to be used for the auto-evaluation. > > > > Obviously 4) is harder than current behaviour and perhaps impossible > > in general but it is achievable for simple cases like in this thread. > > From a user perspective it is definitely what is actually wanted and > > much easier to understand. > > I'm unclear how this works, because if you take my example above with > x = nsimplify("1.4142"), evalf() gave the right answer with the > default precision (15). That is, when everything in the expression is > a non-float, it gives the right answer. However, it seems that as soon > as an expression contains a Float, that Float must have whatever > precision you need set on it. > > My knowledge of how this works internally is rather limited. Most of > what I know is based on my observations on how things work. I've CC'd > Fredrik Johansson. Hopefully he can give better insight into how > things should be working here. > > Aaron Meurer > > > > > -- > > Oscar > > > > -- > > 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 [email protected]. > > To post to this group, send email to [email protected]. > > Visit this group at https://groups.google.com/group/sympy. > > To view this discussion on the web visit > https://groups.google.com/d/msgid/sympy/CAHVvXxRxmU9wrh__88Jw0ERkht3BPzFjo_cu3_iuvRdJdy_BrA%40mail.gmail.com > . > > For more options, visit https://groups.google.com/d/optout. > > -- > 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 [email protected]. > To post to this group, send email to [email protected]. > Visit this group at https://groups.google.com/group/sympy. > To view this discussion on the web visit > https://groups.google.com/d/msgid/sympy/CAKgW%3D6KhqcKoJgoK013m%2BotSRa1cAC%3DOxmtPVh%2B_6C_jGHbmzw%40mail.gmail.com > . > For more options, visit https://groups.google.com/d/optout. > -- 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 [email protected]. To post to this group, send email to [email protected]. Visit this group at https://groups.google.com/group/sympy. To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/CA%2B01voO7R-t6hwL%3DLMF9RoZ2-G68SmpBZdV8k2zQgFb_U4TEoQ%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.
