On Sun, 16 Apr 2023 at 15:52, Trevor Karn <trevor.k.k...@gmail.com> wrote: > > I don't have much understanding of how floating point arithmetic works, but > the argument > > >If you're writing python code, you should expect 2*0.5 to return a > >float. But if you're learning linear algebra for the first time and > >typing a matrix into the Sage notebook, typing 0.5 instead of 1/2 > >should not ruin the entire assignment without so much as a warning. > > seems important to me. I also sometimes worry that Sage seems to be written > for users who are both experts in [insert mathematical field here] and > Python. This prevents (a) mathematical experts who don't know python from > using Sage and (b) more junior students from using sage. Maybe one can make > the argument that mathematical experts should just learn python (although I > would disagree), but I think (b) is a genuine problem. Mathematica doesn't > seem to require the user to be expert in either math or Wolfram language (or > maybe I haven't used it enough). I don't have an actionable complaint here, > but it is something I encounter when helping folks around my math department > with their code. I'm trying to keep it in mind as I develop code.
This hardly requires expert knowledge of Python but rather just the understanding that 0.5 means a floating point number and then some understanding of the implications of floating point numbers on exactness. This is not uniquely a feature of Python by any stretch. The use of a decimal point to denote approximate or floating point numbers is the same in Mathematica, Maple, Maxima, Matlab, and not just Python but most general purpose programming languages. You can see the Mathematica and Maple docs explaining this here: https://www.maplesoft.com/support/help/maple/view.aspx?path=float https://reference.wolfram.com/language/howto/ChangeTheFormatOfNumbers.html Select quotes from there: > > > Enter an approximate real number by explicitly including a decimal point: > > > The presence of a floating-point number in an expression generally > > > implies that the computation will use floating-point evaluation. > > > any calculation mixing exact and approximate numbers gives an approximate > > > result The fact that writing 0.5 (rather than 1/2) implies the use of floating point which in turn implies rounding errors and inexactness is certainly something that can surprise beginners. In the context of Sage it could have been a valid choice not to do that and to have 0.5 mean an exact rational number when it appears as a literal in the user's code. There is no difficulty in making that work any more than making 1/2 return a rational number (since in Python itself 1/2 is a float). This is a design choice though and using decimal literals for floats is useful for anyone who actually wants to do calculations with floats since it means that there is a succinct syntax for floats as well as a separate syntax for exact rationals. > I see that > > sage: A = matrix([[-3, 2, 1 ],[ 2,-4, 4 ], [ 1, 2,-5 ]]) > sage: B = (2*0.5*A) > sage: rank(B) > 3 > > What about floating point arithmetic makes this break? I print (B) and see > > [-3.00000000000000 2.00000000000000 1.00000000000000] > [ 2.00000000000000 -4.00000000000000 4.00000000000000] > [ 1.00000000000000 2.00000000000000 -5.00000000000000] > > which doesn't have any obvious reason to be not rank-2. Could someone ELI5? Arithmetic is needed to be able to compute the rank. With floats that arithmetic is going to be approximate and will have some rounding error. Knowing that the rank is 2 here requires knowing that the third row is *exactly* equal to some linear combination of the first and second but rounding errors will make the linear combinations not be exactly equal. It is basically impossible to compute the rank of a matrix using inexact arithmetic since the tiniest rounding errors will make most matrices appear to be full rank. That does not stop there being floating point routines for computing the rank but they work differently, are inherently heuristic and need thresholds as discussed here: https://numpy.org/doc/stable/reference/generated/numpy.linalg.matrix_rank.html NumPy's matrix_rank function does give the expected answer here and is probably a better implementation of this for machine precision: sage: np.linalg.matrix_rank(B) 2 The Mathematica docs have a caveat about computing the rank of a matrix of floats: https://reference.wolfram.com/language/ref/MatrixRank.html Under the "possible issues" section it says: > > > Use machine arithmetic. Machine numbers cannot distinguish between 9 and > > > 9 + 1e-20 It then shows an example in which the rank of a matrix of floats is computed incorrectly. With that example NumPy fails for the same reason: sage: A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9 + 1e-20]]) sage: A array([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]]) sage: np.linalg.matrix_rank(A) 2 It is not that the matrix_rank function gets anything wrong here but the use of floats even means that 9 + 1e-20 is equal to 9 so the matrix A already has the wrong values before matrix_rank is called. The matrix_rank function returned the exact correct answer for the inputs that it was given. This also shows why converting all floats to rational and then computing the rank does not work in general. If the matrix arrived at the rank function with floats in it then most likely rounding errors have already happened. In that case computing the exact rank based on the exact values of the floats in the matrix is probably not what the user intended. -- Oscar -- You received this message because you are subscribed to the Google Groups "sage-devel" group. To unsubscribe from this group and stop receiving emails from it, send an email to sage-devel+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sage-devel/CAHVvXxRADFToFBuOQJqbme1aLwrrAn2GQNFGBvvRHbVTL0V5jQ%40mail.gmail.com.