From the discussion about bug #5722. COERCE-FLOAT-FUN binds numer: true and that can cause unexpected results when the constructed function contains a call to bfloat, because bfloat is an ordinary function, therefore its argument is evaluated, and numer can cause that argument to be evaluated to an ordinary float, so bfloat sees that number, not the original argument.
Here is the example stated in bug #5722. This first plot shows the expected result. Fortuitously, expr isn't simplified with numer = true before bfloat sees it.
expr:sin(1)^2+cos(1)^2-1;
sc(x):=block([fpprec:floor(x)],float(log(1e-100+abs(bfloat(expr)))/log(10.0)));
plot2d(sc,[i,5,100]);
This second one shows the bug:
expr:sin(1)^2+cos(1)^2-1;
sc(x):=block([fpprec:floor(x)],float(log(1e-100+abs(bfloat(''expr)))/log(10.0)));
plot2d(sc,[i,5,100]);
The expected behavior is produced by protecting the call to bfloat from COERCE-FLOAT-FUN's binding of numer. This third example shows the expected result again:
expr:sin(1)^2+cos(1)^2-1;
sc(x):=block([fpprec:floor(x), numer: false],
float(log(1e-100+abs(bfloat(''expr)))/log(10.0)));
plot2d(sc,[i,5,100]);
I'm not sure what the solution is here. There are at least a couple of possibilities:
(1) Update the documentation for plot2d and any other callers of COERCE-FLOAT-FUN to say that the constructed function binds numer: true. (I think it should just say that and let that be enough. Explaining that that will interfere with bfloat and furthermore enclosing bfloat within block([numer: false], ...) is a bridge too far, I believe; in every context, there are innumerable things that someone could be trying to do, and in the interest of keeping the reference manual comprehensible, we must steer away from trying to address them.)
(2) Change bfloat so that it is an argument-quoting function, and it evaluates its argument in an environment with numer bound to false. (I'm not saying I want to do this. I'm just saying it is a possibility.)
I had Claude look into this. What it found:
The
numer: truecomes fromCOERCE-MAXIMA-FUNCTION-OR-MAXIMA-LAMBDA(andCOERCE-LISP-FUNCTION-OR-LISP-LAMBDAfor translated functions), which bind it around the call of a function given by name or as a lambda. Expressions take another path. These two bind it forCOERCE-BFLOAT-FUNas well, so withfpprec: 40,bf_find_root(lambda([x], x^2 - %pi), 1, 2)is off by3.5e-17whilebf_find_root(x^2 - %pi, x, 1, 2)is exact. Same forbromberg.Its proposed fix:
numer(falsefor bigfloats).floatconverts the result as before.floatreturns, since that can be an unsimplified power like(-6.14)^(1/3). Otherwisefoo17in rtest8.mac, passed by name, goes non-numeric. This also fixes translated functions likeh(x) := (x - %pi)^(1/3), which had no values forx < %pi.numer: truefor expressions. Without it, expressions with constants like%pievaluate 2 to 4 times slower.plot2ddocs: expressions are evaluated withnumer: true, functions with the currentnumer.Making
bfloatquote its argument only helps a literalbfloat(''expr), notblock([e : ''expr], bfloat(e)), so Claude advised against it.