Skip to content
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

'-9/4 x' vs '9/4 x' #2370

Closed
fpiou opened this issue Dec 26, 2021 · 9 comments · Fixed by #2460
Closed

'-9/4 x' vs '9/4 x' #2370

fpiou opened this issue Dec 26, 2021 · 9 comments · Fixed by #2460

Comments

@fpiou
Copy link

fpiou commented Dec 26, 2021

Hi
I have an issue with this because of a different traitement :

math.parse('-9/4 x').toString() ----> '-9 / (4 x)'
math.parse('9/4 x').toString() ----> '9/4 x'

My preference is : math.parse('-9/4 x').toString() ----> '-9 / 4 x'

Is it an issue or a rule that i don't understand ?

@fpiou
Copy link
Author

fpiou commented Dec 29, 2021

https://mathjs.org/docs/expressions/syntax.html

I know that some people write pi/2pi and mean pi/(2pi) but it's only possible in a mathematical text reading by human who are able to anderstand.
With an algorithm, we have to be clear if we want pi/(2pi).
By the way, 1/2pi and pi/2pi are not interpretate the same way in mathjs.

> math.parse('1/2pi').toString()
'1 / 2 pi'
> math.parse('pi/2pi').toString()
'pi / (2 pi)'

@josdejong
Copy link
Owner

Thanks for your suggestion @fpiou. Your proposal makes sense to me, I'm not sure if this was a conscious decision to choose this behavior. It may be that changing this behavior would break other cases, so we need to be careful. See #792 for the in-depth discussion on this topic.

math.parse('9/4x').toString()
"9 / 4 x"
math.parse('2-9/4x').toString()
"2 - 9 / 4 x"
math.parse('-9/4x').toString()
"-9 / (4 x)" -> more logical would be "-9 / 4 x"

Anyone interested in trying this out and working out a PR?

@gwhitney
Copy link
Collaborator

gwhitney commented Feb 3, 2022

Note that the treatment of 9/4 x is the one that is a bit special; all of the following group the denominator more tightly: +9/4 x, 9/+4 x, 9/-4 x, 4/3! x, i.e., the first parses like +9/(4x) and all the rest are similar.

@gwhitney
Copy link
Collaborator

gwhitney commented Feb 7, 2022

Now that this is the preferred resolution of #1431, there needs to be a decision as to the extent to which quotients preceding a symbol or a parenthesized expression will bind more tightly and be interpreted as implicit multiplication. Currently only c1/c2 x does, where cN is a bare numerical constant and x is a symbol or parenthesis. Clearly this issue expects -c1/c2 x to be so interpreted as well. By symmetry, it seems clear to me that +c1/c2 x should as well. But other possibilities remain judgment calls:

  1. c1/-c2 x and c1/+c2 x
  2. Sc1/Sc2 where S is either sign, + or -
  3. c1!/c2 x where ! is factorial
  4. c1/c2! x
  5. c1!/c2! x
  6. +c1!/c2 x and c1/+c2! etc.
  7. Uc1U/Uc2U x where UcU stands for any arbitrary combination of prefix or postfix unary operators applied to a bare numerical constant. (I guess the only relevant unary operators are unary plus and minus, factorial, percentage, and bitwise not. There's also transpose, but it doesn't really apply to numbers.)
  8. (c1)/c2 x, c1/(c2) x, and (c1)/(c2) x.

I am assuming that the parenthesized expressions in (8) should not be interpreted by this special fraction implicit multiplication rule, i.e., they should all parse to c1/(c2*x), but I am really not sure where mathjs would ideally draw the line in the progression of cases 1-7. I have identified the spot where the code would need to change and will be happy to try a PR if you can provide guidance as to what the desired behaviors are. Thanks!

@josdejong
Copy link
Owner

🤔 Those are interesting examples. I'm trying to extract a generic rule from all the examples that we're sharing here.

I think we must understand the intention of people when writing something like -9/4x. What we're talking about here I think is writing a single value as a fraction. You normally do that with a unary in front of it like -9/4, but not at the denominator like 9/-4. So what a user means with -9/4x is probably best interpreted as (-(9/4))*x. This would be effectively the same as ((-9)/4)*x so maybe we should just go with that, since interpreting -9/4x as (-(9/4))*x would introduce extra inconsistency with this special case where the unary operator gets lower precedence than division.

So, I think it boils down to the following rule: when having a division followed by an implicit multiplication, the division gets higher precedence over the implicit multiplication when (a) the numerator is a constant with optionally a unary prefix, and (b) the denominator is a constant.

This would leave all your examples 1-8 as is because there are not matching this rule (not dealing with a plain constant in the denominator, or not dealing with a plain constant with optional unary prefix in the numerator).

Does this reasoning make sense?

@gwhitney
Copy link
Collaborator

Yes, I was just looking for a clear plan here. The only case I would like to specifically re-check is (3) as that also involves just a unary operator in the numerator: you would like -9/4x to parse as ((-9)/4)x but 9!/4x to parse as (9!)/(4x), because ! is a postfix as opposed to prefix unary operator? And so, just for the sake of completeness, what about the only other prefix unary operator (currently), namely bitwise negation ~? Should ~9/4x parse as ((~9)/4)x or as (~9)/(4x)? Thanks.

@josdejong
Copy link
Owner

👍

Thanks. The new behavior is indeed "inconsistent" in a way, when you look at a postfix operator like ! which is now handled differently than a prefix operator like -. I'm afraid though that no matter what rule we chose, it will be inconsistent anyway regarding other rules.

Good question if we want to apply this new rule to all postfix operators (-, +, ~) or only the unary minus. I have a slight preference to apply it to all postfix operators (that feels most consistent, or, least inconsistent). Do you have a preference Glen?

@gwhitney
Copy link
Collaborator

I think + and - should be handled the same way. I have no preference as to whether ~ should be the same as these or not, as ~9/4x is just a bizarre expression. (I rarely have occasion to use bitwise negation in the first place). The code might be very marginally simpler if all prefix unary operators are treated the same way.

@josdejong
Copy link
Owner

yes ~9/4x is just odd 😂 , but well, the parser should parse it somehow if a user enters it for whatever reason.

The code might be very marginally simpler if all prefix unary operators are treated the same way.

Ok let's go for that 👍 .

So then the rule can be described as: when having a division followed by an implicit multiplication, the division gets higher precedence over the implicit multiplication when (a) the numerator is a constant with optionally a prefix operator (-, +, ~), and (b) the denominator is a constant.

gwhitney added a commit to gwhitney/mathjs that referenced this issue Mar 3, 2022
  As per the discussion in josdejong#2370, the amended "Rule 2" is
  "when having a division followed by an implicit multiplication, the
   division gets higher precedence over the implicit multiplication when
   (a) the numerator is a constant with optionally a
       prefix operator (-, +, ~), and
   (b) the denominator is a constant."
  This commit implements that behavior and adds tests for it.
  Resolves josdejong#2370.
gwhitney added a commit to gwhitney/mathjs that referenced this issue Mar 8, 2022
  As per the discussion in josdejong#2370, the amended "Rule 2" is
  "when having a division followed by an implicit multiplication, the
   division gets higher precedence over the implicit multiplication when
   (a) the numerator is a constant with optionally a
       prefix operator (-, +, ~), and
   (b) the denominator is a constant."
  This commit implements that behavior and adds tests for it.
  Resolves josdejong#2370.
gwhitney added a commit that referenced this issue Apr 13, 2022
  As per the discussion in #2370, the amended "Rule 2" is
  "when having a division followed by an implicit multiplication, the
   division gets higher precedence over the implicit multiplication when
   (a) the numerator is a constant with optionally a
       prefix operator (-, +, ~), and
   (b) the denominator is a constant."
  This commit implements that behavior and adds tests for it.
  Resolves #2370.
gwhitney added a commit that referenced this issue Apr 30, 2022
  As per the discussion in #2370, the amended "Rule 2" is
  "when having a division followed by an implicit multiplication, the
   division gets higher precedence over the implicit multiplication when
   (a) the numerator is a constant with optionally a
       prefix operator (-, +, ~), and
   (b) the denominator is a constant."
  This commit implements that behavior and adds tests for it.
  Resolves #2370.
gwhitney added a commit that referenced this issue May 12, 2022
  As per the discussion in #2370, the amended "Rule 2" is
  "when having a division followed by an implicit multiplication, the
   division gets higher precedence over the implicit multiplication when
   (a) the numerator is a constant with optionally a
       prefix operator (-, +, ~), and
   (b) the denominator is a constant."
  This commit implements that behavior and adds tests for it.
  Resolves #2370.
gwhitney added a commit that referenced this issue May 31, 2022
  As per the discussion in #2370, the amended "Rule 2" is
  "when having a division followed by an implicit multiplication, the
   division gets higher precedence over the implicit multiplication when
   (a) the numerator is a constant with optionally a
       prefix operator (-, +, ~), and
   (b) the denominator is a constant."
  This commit implements that behavior and adds tests for it.
  Resolves #2370.
gwhitney added a commit that referenced this issue May 31, 2022
  As per the discussion in #2370, the amended "Rule 2" is
  "when having a division followed by an implicit multiplication, the
   division gets higher precedence over the implicit multiplication when
   (a) the numerator is a constant with optionally a
       prefix operator (-, +, ~), and
   (b) the denominator is a constant."
  This commit implements that behavior and adds tests for it.
  Resolves #2370.
gwhitney added a commit that referenced this issue Jul 13, 2022
  As per the discussion in #2370, the amended "Rule 2" is
  "when having a division followed by an implicit multiplication, the
   division gets higher precedence over the implicit multiplication when
   (a) the numerator is a constant with optionally a
       prefix operator (-, +, ~), and
   (b) the denominator is a constant."
  This commit implements that behavior and adds tests for it.
  Resolves #2370.
gwhitney added a commit that referenced this issue Jul 15, 2022
  As per the discussion in #2370, the amended "Rule 2" is
  "when having a division followed by an implicit multiplication, the
   division gets higher precedence over the implicit multiplication when
   (a) the numerator is a constant with optionally a
       prefix operator (-, +, ~), and
   (b) the denominator is a constant."
  This commit implements that behavior and adds tests for it.
  Resolves #2370.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants