Repository navigation
An unknown function name is silently read as a product, so log10(x) becomes log^10 * x #733
Description
Activity
- added a commit that references this issue
on Aug 5, 2026 The defect half of this is fixed in #734, merged to master as 318ac9f.
before after log10(100)log ^ 10 * 1002log10(1000)log ^ 10 * 10003log2(8)log ^ 2 * 83log2(1024)log ^ 2 * 102410Two grammar rules mapping to
MathS.Log(10, arg)andMathS.Log(2, arg), so they are the same function as the spelling that already worked rather than merely each being defined --log10(x)andlog(x)parse to one tree, and the test asserts that rather than asserting each value separately.Only the exact name followed by a bracket is the function, as for every other function in the grammar:
log2xis still the implicit powerlog^2 * x,log10stilllog^10, andlogx(y)andlog3(x)are still the implicit products they were. The one- and two-argumentlogare untouched.Leaving this open for the rest, which is the part that is not a defect:
floor,ceil,round,erf,re,im,conjugate,min,max,gcdandlcmname functions AngouriMath does not have, so a silent product is the ordinary consequence of implicit multiplication being a feature -- refusing every unknown name would breaka(b + c). Those are feature requests, and each wants its own judgement about whether the library should have the function at all.The argument-count inconsistency in the report is also still there and unaddressed: a one-argument call to a missing name is silent, a two-argument one raises. Worth knowing before treating a parse error as the way a missing function shows up.
Tests in
LogBaseNamesParsedTest.cs.- added a commit that references this issue
on Aug 5, 2026 Partly landed, and the example in the title is now fixed — leaving a note so the issue is not read as untouched.
Done:
was is log10(100)log ^ 10 * 1002(#734)log2(8)log ^ 2 * 83(#734)factorial(5)factorial * 5120(#737)Still open, and not a grammar line. Measured on
af766b22:parse(floor(x)) => floor * x <- silent parse(ceil(x)) => ceil * x <- silent parse(round(x)) => round * x <- silent parse(min(3,5)) => UnhandledParseException parse(max(3,5)) => UnhandledParseException parse(gcd(12,18)) => UnhandledParseExceptionThe three landed names each had a node behind them already, so adding them was a grammar entry and a test.
floor,ceilandroundhave no node in the library at all — only an internalEDecimal.Floorhelper — so reading them means a node through parsing, evaluation, simplification, differentiation, compilation, LaTeX and the F# wrapper. That is the same plumbing #402 wants for modulus, and it should probably be costed with it rather than treated as more of this issue.The silent ones are worth separating from the loud ones:
min(3,5)raising a parse error tells you something is wrong, whereasfloor(x)quietly becomingfloor * xgives an answer to a different question. Implicit multiplication is why it cannot simply be made an error —x(y+1)is a legitimate product — so the fix really is "add the node", not "reject unknown names".- added a commit that references this issue
on Aug 5, 2026 Correcting my comment above — it says
floor,ceilandroundare still read silently as products, and that is no longer true. The silent misreading this issue is titled for is gone.Measured on stock
master(184dd5a), every name from that list is now refused by name, with a message saying what is missing:parse(floor(x)) => UnrecognizedFunctionParseException: there is no function floor: AngouriMath has no rounding functions. It is refused by name rather than read as the product of a variable named floor with its argument, which is what an unknown name followed by a bracket would otherwise mean parse(ceil(x)) => ... no rounding functions parse(round(x)) => ... no rounding functions parse(erf(x)) => ... no error function parse(conjugate(x)) => ... no complex conjugate as a symbolic function parse(min(3, 5)) => ... no minimum or maximum function parse(gcd(12, 18)) => ... no greatest common divisor as a symbolic functionAnd implicit multiplication, which is the reason unknown names could not simply be rejected, still parses:
parse(x(y + 1)) => x * (y + 1)So the mechanism in the report — a one-argument call falling through to implicit multiplication and quietly answering a different question — no longer applies to any of these names, and the loud/silent distinction I drew above has been resolved in favour of loud.
What is genuinely left is the scope question, which is what this issue said from the start it was really about: which of
floor,ceil,round,erf,conjugate,re,im,min,max,gcdshould exist as nodes. That is a naming and design call per name, not a grammar line, and each wants its own answer —floorandroundcarry the same plumbing cost as the modulus in #402 and are probably best costed with it.I would suggest closing this one as fixed and letting the individual functions be requested where they are wanted, but it is your call and I have not touched it.
Yea the inclusion of those functions belong to their own issue
Closing: the defect in the title is fixed. Re-measured on
master(21f0d16):was now log10(x)log ^ 10 * xlog(10, x)✅exp(x)a product e ^ x✅floor(x)floor * x, silentlyUnrecognizedFunctionParseException, by name ✅An unknown name followed by a bracket is no longer read as a product. Where the function does not exist, it is refused by name with a message saying what is missing, which is the thing this issue was opened about.
Per @Happypig375 — "the inclusion of those functions belong to their own issue" — the remaining work is tracked in #809:
floor,ceil,round,min,maxandgcdare still absent, and each needs a design decision rather than a grammar line.
Split out of #730, which was one instance of this. Filing the sweep rather than fixing it, because what to do about most of these is a naming call rather than a defect.
The mechanism
A name the grammar does not know, followed by
(, falls through to implicit multiplication — the rule that letsa(b + c)meana * (b + c). For a one-argument call this never errors; it silently produces a product with an undeclared variable. Measured on master (7f83a82):A two-argument call fails loudly instead, because
name * (x, y)is not a valid parse:That inconsistency is worth noting on its own: whether a missing name is reported depends on how many arguments the caller passed, not on anything about the name.
The part that is a defect
Most of the names above are functions AngouriMath simply does not have, and a silent product is the ordinary consequence of implicit multiplication being a feature. You cannot refuse every unknown name without breaking
a(b + c).But two of them name something the library does have, and those are the same shape as #730:
log(100)is already 2 andlog(2, 8)is already 3, so nothing is missing but the spelling. These are worse than the others to read, too:log10lexes as the variablelogfollowed by10, andx2meansx^2by design, so the result is a power of an undeclared variable rather than a product with one.log10andlog2are standard in C, Python, numpy and MATLAB.Suggested fix
Add
log10(andlog2(toAngouriMath.gasMathS.Log(10, arg)andMathS.Log(2, arg)— the same shape as theexp(rule added in #731. The rest of the names above are feature requests for functions that do not exist yet (floor,ceil,round,min,max,gcd,lcm, …) and should be judged separately.Found by sweeping common CAS function names past the parser after #730, which was the same defect for
exp.