Bad parse for adding percentages
It turns out the expression 10% + 20% is parsed right now as 10 % ((+20) / 100) (so: the first % is interpreted as mod).
Originally posted by @josdejong in https://github.com/josdejong/mathjs/discussions/2861#discussioncomment-14752338
The consensus in the referenced discussion seems to be that the desired parse/behavior for this is (10%) + (20%) behaving as 0.1 + 0.2 to yield a value of 0.3. The current parse is just bad from the user perspective, and the previous parse of ((10%) + 20%) as 0.1 + 20% to yield 0.12 as the final value was a bit more understandable but still not generally desirable. Note there are lots more edge cases to consider in the attached discussion, but this one really rises to the level of a bug that deserves more rapid attention -- and certainly whatever cases are resolved need to be enshrined in unit tests so we avoid future regressions; these expressions have gone through a lot of iterations :/
Is there any chance that it would help the situation to make % a Unit symbol for a dimensionless unit with a value of 0.01, and implement a special rule in the addition operation for a pure number and a Unit with the unit of percent that it does the funky multiplication by one plus the percentage thing? (In my mind, that's really what's going on...) Note this special number + unit of percent operation is not commutative: 10 + 30% is 13, but 30% + 10 has to come out as 10.3, presumably. Anyhow, it occurs to me that if the two percents in 10% + 20% can be parsed as unit symbols, the natural outcome will be 30 in this same unit, which would then have the nice advantage of displaying as 30%, which is probably what would really be nicest for the user anyway.
Added: Presumably % would be one alias for a unit also named percent, so you could also write 10 percent + 20 percent and it would work as expected.
It may work to treat % as a unit with just a value 0.01, or even simpler: a constant with that value. However that opens up a lot of options to use this constant in a wrong or unexpected way like dividing a value by % or so. So it may be best to treat it as a special syntax and limit parsing of % to the supported use cases.
It may work to treat
%as a unit with just a value 0.01, or even simpler: a constant with that value. However that opens up a lot of options to use this constant in a wrong or unexpected way like dividing a value by%or so. So it may be best to treat it as a special syntax and limit parsing of%to the supported use cases.
Ah yes I had not thought too much about the consequences of % as a bare unit. But nevertheless it still might be that an internal representation as a unit percent could be useful. After all, since the character % is also the mod operator, the parsing of % as a unit abbreviation, if that ends up being how it is implemented, would have to be special, and could preclude its use as a bare unit in something like 10 / % (even though 10 / second is perfectly well allowed, and perhaps 10/percent could also be allowed even if it is silly). I think that percent as a unit rather than as just a numerical constant would be necessary to allow a special addition operation between a number and a Unit in percent; I don't see how we could have a different operation for adding two numbers depending on whether the second number "came from" a special constant number. The original motivation for the suggestion is that for Units with matching dimensions, it is OK to add them, and this would exactly work for percents; but it is currently disallowed to add a number and a Unit, even if the latter is unitless. So extending that operation to be defined for a number and a percent Unit (only in that order!) would not conflict with any existing operations, and produce the correct answer. I think this convention could handle a lot of cases, e.g.
10 + 40% + 50% == (10 + 40%) + 50% == 14 + 50% == 21, (successive markups) and
10 + (40% + 50%) == 10 + 90% == 19 (adding percentages before a single markup), etc.
So I guess my proposal could best be summarized as representing the percentage as a mathjs entity, which undergoes the usual operations (but has different results than a plain number in some cases), vs. the current approach that as far as I can see attempts to rewrite the parse tree to reflect what we want to interpret the percent symbol as "doing". I raise this proposal in the spirit of brainstorming, given the facts that mathjs has had significant ongoing difficulties with the current "syntax-tree rewriting" approach. Whoever attacks this issue can consider whether this alternate proposal has practical merit.
Note that as far as I can tell we currently have no unit symbols with BASE_UNIT.NONE, since the closest would be degree but mathjs has adopted the alternate convention (different for example from SI) that angle is a fundamental dimension like mass, as opposed to essentially a number. (Although I do think think the mathjs convention faces some hurdles, in that SI can fudge the distinction between hertz as "cycles per second" and "occurrences per second" whereas mathjs cannot: it defines "hertz" as "per second", so that 3 cycle / second is not equal to 3 hertz, which may come as a surprise to some users.) Anyhow, it does mean that there is a relatively open field as to how to interpret operations on "unitless units".
It is definitely an interesting idea to implement % as a unit, worth exporing.