-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Made pow-operator right associative. #2
Conversation
The scheme outlined above does not work with expressions consisting of more than 3 terms: |
Thanks for pointing this out! I grew up with Matlab and Octave, which evaluate the power operator left associative, I just took that behavior for granted... I have commited a solution in the develop branch, see e9bddfd Parser.prototype.parse_pow = function (scope) {
var nodes = [
this.parse_factorial(scope)
];
// stack all operands of a chained power operator (like '2^3^3')
while (this.token == '^') {
this.getToken();
nodes.push(this.parse_factorial(scope));
}
// evaluate the operands from right to left (right associative)
var node = nodes.pop();
while (nodes.length) {
var leftNode = nodes.pop();
var name = '^';
var fn = pow;
var params = [leftNode, node];
node = new Symbol(name, fn, params);
}
return node;
}; |
Cool, thanks Jos! |
There is another, similar issue: unary minus. How to interpret |
Personally, I like to follow Python's rules in this regard, where the power operator has a higher precedence than the unary minus:
But, as you mention, there's no strict convention about this. Your call! |
I think I'm going to list the precedence choices of the most used math/programming languages and then make a choice to consistently follow one of the two camps. So far that has been the matlab/octave camp. Let's see which camp matches best with the user community that math.js aims to reach. |
Ok, I did some checking. Left or right associative exponentiation, for example
Precedence of unary minus over exponentiation, for example
As math.js is library for JavaScript (a scripting language), I think it's good to follow the scripting languages in this respect: python, ruby, perl, etc. So I will go for the right associative power with higher precedence than unary minus. Code changes are on the way... |
Hi Jos, as usual with your work: great stuff! I did find a little bug though: your parser handles the power operator like any other binary operator (left associative), while the power operator is (in most cases) right associative. I.e., the expression
a^b^c
is now being parsed as:while it should be parsed as:
Since the parser is a LL (top-down) parser, this desired structure is a bit tricky to get. A possible solution:
For the input
"a^b^c"
the parser would first create(^ a b)
and would then encounter"^c"
. Now instead of creating the AST(^ (^ a b) c)
, you do the following insideParser.prototype.parse_pow
:(^ a b)
(nodea
) the left child of the new node:(^ a (^ . b))
b
, to the left:(^ a (^ b . ))
c
, to the right ofb
:(^ a (^ b c))
My pull request has the scheme above implemented, including some unit tests.
Cheers,
Bart.