Open WarrenWeckesser opened 1 week ago
The log1p
function looks like it takes a double
. Did you mean to write log1pl
? Do you get the same results with log1pl
?
BTW, the code for this function is part of the upstream musl project and lives in system/lib/libc/musl/src/math/log1pl.c
.
If I am reading https://en.cppreference.com/w/cpp/numeric/math/log1p correctly, log1p
should be overloaded to accept all three floating point types. The code works as expected with other C++ compilers.
I tried with log1pl
, and still got the result corresponding to the double
calculation.
If I am reading https://en.cppreference.com/w/cpp/numeric/math/log1p correctly,
log1p
should be overloaded to accept all three floating point types. The code works as expected with other C++ compilers.I tried with
log1pl
, and still got the result corresponding to thedouble
calculation.
Sounds like the problem is perhaps with the implementation of log1pl
. Perhaps you could re-write the example in pure C to show that the issue with musl (the underlying C library) rather than with libc++. Assuming that the issue can be reproduced in pure C then I think the next step would be to take a look at the implementation of log1pl to see if there is anything obvious stopping it from working with 128-bit float.
BTW, Wasm doesn't actually support 128-bit floats at the instruction level so any time you use long doulbe you will end up pulling in software fallbacks which are very slow and requires a bunch of extra code. If you can instead avoid long double
in your code that would probably give you better results under wasm. is that possible in your case?
is that possible in your case?
I'm actually working on NumPy, and one of the platforms that is included in NumPy's test suite is pyodide, and pyodide is built on emscripten. I had a unit test failing on the pyodide platform, so I've had to dig into how emscripten handles floating point. The calculation that I'm working on loses precision for certain regions of the input values, and one way to avoid that loss is to using higher precision variables when computing in that region.
It looks like musl doesn't implement full long double precision (i.e. 113 bit mantissa). From log1pl.c:
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
// TODO: broken implementation to make things compile
long double log1pl(long double x)
{
return log1p(x);
}
#endif
Other functions (e.g. logl
, expl
, etc) have the same behavior.
Do you have some way to disable long double
support in NumPy at compile time? Since it doesn't exist at the Wasm level you might as well fall back to using whatever emulation support NumPy has internally for greater precision floating point.
NumPy doesn't have any emulation for long double
. Whatever the underlying compiler provides is what is used. So the underlying implementation of long double
might be: the same as double
, 80 bit extended precision, IEEE float128, or IBM double-double. NumPy can and does override implementations of specific functions in the standard library if it is found that the standard library version has deficiencies. So in theory, NumPy could replace all these bad musl functions with different implementations. But that means developing (or finding license-compatible versions of) float128 versions of a lot of functions, and that should really be done in musl, not NumPy.
I think I can guess the source of the problem, but I want to be sure.
check_log1p.cpp
Compile and run:
The value of
x
is small enough thatlog1p(x)
should equalx
. The last two lines being the same shows that the calculation ofstd::log1p(x)
is being done withdouble
, notlong double
.My guess is that, even though you provide 113 bits precision in
long double
, yourstd
math library does not support that precision. Is that correct?The silent downcast to
double
is a nasty wart in the API. Is there any way to enable an error or warning when that happens?Version of emscripten/emsdk:
Full link command and output with
-v
appended:Here's the compile command with
-v
added: