-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implicit multiplication and unit division #792
Comments
Implicit multiplication can be tricky indeed, and I agree that it doesn't always work as expected. What should The current behavior is that implicit multiplication has the same precedence as explicit multiplication and division:
I just tried this in google, which has a bit different behavior, more in line with what we typically would expect:
I'm not sure about the exact rules in which cases googles calculator gives implicit multiplication either higher or lower precedence. Maybe it's when the implicit multiplication is preceded by a division which has either a number or symbol as left hand side. We could give this some more thought and see whether this would be a good idea for math.js too. |
Maybe the google calculator tries to match units greedy to left hand nodes or numbers? |
I would love to see a good resolution to this issue. Doing some testing of my own on Google, this is what I found:
Definitely some interesting things going on there. It seems like operators follow this precedence, from highest to lowest:
Rule 2 would make Edit: If implemented, this would obviously be a breaking change for v4 (or just configurable by a global setting). |
Would be excellent if implemented and made configurable, so does not break the existing apps that rely on the older behaviour. Or perhaps we can just merge the tokens of the following: "50 kg" (as in, number followed by a unit), into a single token which is then parsed as usual by the expression engine. |
Yes I also would like to make some changes here. It will be breaking changes indeed, I've added this topic to the list in #682. Whether it's much work or not depends on what we will change exactly, if there are some complicated look aheads needed it may be more work. @ericman314 do you think the rules you found are consistent, or are you still unsure? Can you expand the list of rules you found with the places of explicit addition/subtraction and explicit multiplication/division just to get things clear? @robinrodricks I think we should make a hard choice here and not make this behavior configurable, I think that would result in a confusing mess. |
After thinking about this more, I would only propose changing one thing. Implicit multiplication between numbers and symbols, or symbols and symbols, would take higher precedence than regular multiplication and division. Currently it has equal precedence. Current operator precedence:
Proposed operator precedence:
Examples:
If any users are bothered by the higher precedence of implicit multiplication, they would always be able to add back in the I've also done a little more investigating into Google's behavior for fractions. As impressive as it is, we would not reproduce that behavior right now. We could add this later, though I doubt there would be much interest for it. For reference, here is Google's operator precedence from what I've observed:
Google's different precedence for simple and compound fractions leads to some pretty intelligent behavior. |
Thanks for thinking this through @ericman314 ! I think you're right, giving implicit multiplication higher precedence than explicit multiplication/division will solve most of the issue. More advanced rules can be nice, but can also make the behavior less predictable for users, I'm not sure whether that's needed. You specifically mention implicit multiplication of numbers and symbols, or symbols and symbols. Does that mean that you would like to keep the original behavior for other forms of implicit multiplication? How about implicit multiplication between numbers and parenthesis ( |
You're right. To be consistent we should make all forms of implicit multiplication higher precedence, so there's no question how an expression will be parsed. That way the precedence of the implicit multiplication "operator" doesn't depend on the types of the operands. |
Yes that makes sense, just the simple rule implicit multiplication has higher precedence than explicit multiplication and division. That may be best. I'm still a bit in doublt about |
I'm lurking here. I am assuming that if you use parentheses there is no
issue, right?
…On Wed, Oct 18, 2017 at 4:56 PM, Jos de Jong ***@***.***> wrote:
Yes that makes sense, just the simple rule implicit multiplication has
higher precedence than explicit multiplication and division. That may be
best.
I'm still a bit in doublt about 1/2 hour being evaluated as 1 / (2 * hour),
don't you think that will become a new pitfall?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#792 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AA-AmhwfCd2bdmSCy-XIoRNYhCk2cCYCks5stmYHgaJpZM4L3Rsp>
.
--
B.F. Lyon, Ph.D.
http://bit.ly/bflyon-viz-summary
|
@nowherenearithaca If you use parentheses, it is not ambiguous and you are safe. Also at the moment, all kinds of multiplication have the same precedence (from left to right), but that would change if ericman314's suggestion would be implemented. But if you explicitly specify the multiplication via '*' it will still behave the same way it does currently. |
@josdejong that is indeed a valid concern. With my engineering background, I would type |
@josdejong, I've implemented the new parsing rules for implicit multiplication and for fractions in my own branch here: https://github.com/ericman314/mathjs/blob/implicit-multiplication/lib/expression/parse.js It's not ready for a PR yet but here is the comparison between the two files: develop...ericman314:implicit-multiplication Try installing that file and running the unit tests to see how the new parsing rules change things. |
That's great @ericman314 ! I will play around with it this week to see how it looks/feels. |
Thanks @ericman314 for the fantastic solution to this problem! It would be great to move towards Google in terms of parsing behavior. Can't wait for the PR to play with the final version :) |
@ericman314 I'm working out all breaking changes for |
I'm happy to finish it. Should I submit the PR to the v4 branch? |
Thanks! Yes we will need to merge this in v4 since it will be a breaking change. |
So to be clear, there are two proposed changes to the parsing rules here:
At present, Since this is going to be a breaking change there are a few tests that are failing. But I did not expect this test to fail:
The expression now returns Here's a more illustrative example:
In the first two lines, The reality is I can't make heads or tails of how Google is choosing to parse fractions. Sometimes they have higher precedence and sometimes not. For example, Unless we can make rule 2 context-aware, I don't see how we can avoid the unexpected behavior. I see our options as first, we could remove rule 2, or second, try to apply rule 2 only where it makes sense. |
Thanks for your clear summary. I think we all agree on rule 1. We have to give rule 2. more thought I think. I don't fully understand why two explicit divisions like How about the following rule 2:
So some examples would give:
|
@ericman314 do you have an idea when you will have time to work on the implicit multiplication? |
I think I can get to it this weekend.
…On Feb 2, 2018 3:00 PM, "Jos de Jong" ***@***.***> wrote:
@ericman314 <https://github.com/ericman314> do you have an idea when you
will have time to work on the implicit multiplication?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#792 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AGDTkTc9dkcOg8ZGVLRXTVRzBt1gBWIZks5tQ4WPgaJpZM4L3Rsp>
.
|
After seeing the strange results of rule 2 in repeated divisions, I'm having doubts. In my opinion, when a user writes an expression, it should be absolutely clear to him/her how it will be parsed. I think if we try to implement rule 2, no matter how clever we are (and I thought my solution above was pretty clever), we will eventually find an example that results in unexpected behavior. @josdejong, I know you might disagree with me here, but my vote is to not implement rule 2 at all and to make rule 1 optional: math.config({ promoteImplicit: true }) Setting that option would promote the precedence of implicit multiplications above that of explicit multiplication and division. Because the default setting is |
As a start, I submitted PR #1034 which adds a config option for implicit multiplication, but I'm happy to modify it as necessary according to whatever our final decision is here. |
Thanks for exploring Solution 2 @ericman314 . I totally believe you that this gives weird, hard to understand cases. That's really unfortunate, I had hoped we could find a nice solution which feels natural and consistent. Just for my understanding, can you post one or two of these weird cases? Just to be sure we're on the same page: did you implement Solution 2 as described in your comment #792 (comment), or as described in my proposal here #792 (comment)? Let me try to summarize the current state of the discussion:
What may help is to try to get a clear picture of the audience and their expectations.
The user group that has most benefit for a change in implicit multiplication is group C "regular users". I'm afraid that we will not really help them since both solutions that we can offer them will stil give unexpected results in certain cases as explained in (5.) |
Jos, thanks for clarifying your position. I jumped to conclusions without trying your suggestion. To be honest I wasn't exactly sure how to do it. I suppose the parser would simply look ahead a few tokens to find the pattern The reason my first implementation of rule 2 failed was that it was being applied in instances where implicit multiplication wasn't even happening, such as I will try your suggestion. Hopefully I can get it to work. I've never seen a parser written like in
|
I think you're right with your last three rules. We may have to also catch
In that Solution 2 proposal my idea was that implicit multiplication would never have higher precedence except in the special case of I haven't yet looked into the code on how to implement such a "lookahead", but it may be as easy as adding a check for our pattern |
I've actually just finished implementing it, with implicit multiplication always having higher precedence except for the pattern
And my personal favorite also works:
The only one that doesn't match your suggestion is If you're OK with this behavior I'll go ahead and write the tests and edit the docs. Edit: Here is the diff if you're interested in seeing how I did the look ahead. |
that. is. awesome! The example How does |
About unit testing, I was just thinking, we should rewrite tests like these: assert.equal(parseAndEval('1/2a', {a:2}), 1); with something like: assert.equal(parseAndStringifyWithParens('1/2a'), '(1 / 2) a'); that's much easier to understand instead of having to calculate and compare the result. |
Agreed. I'll get started on the tests. Also, when stringifying a parsed tree, do we need to alter when parentheses are displayed to account for the new precedence? |
ah, of course! That's good. (We could later on implement support for implicit addition in a case like
I think we can keep it as it is, we have the option I've gone through your list with examples again, I'm really happy with this behavior, it all looks logical to me! I'm very curious to your implementation. There will always some weird edge cases, but for all "typical" inputs it looks great. As for the edge cases: that's the risk of working with implicit multiplication. These edge cases are not a "new" problem, we already had this problem, I just think we made the problem smaller. The predictability is lower because we have more complicated rules now, but I think that weights off against better handling most typical use cases. |
Ouch, there's 590 instances of |
No need to replace all, in many cases |
If you're curious, here's my version of |
I've submitted the PR but couldn't figure out how to leave package-lock.json alone. |
Great! going to review your work immediately. yeah, package.lock can easily give huge changes or merge conflicts though it looks like it improved with the latest versions of npm. No problem! |
Implemented via #1036 |
Hi, I tried following in the live parser on http://mathjs.org/#demo
17 h / 1h
and the result was17 h^2
which was kind of unexpected ^^,Is it possible to have precedence between 1 and h (or units in general) before the implizit multiplication?
The text was updated successfully, but these errors were encountered: