exp2f in MUSL is correct, but it *does* depend on precise float32
semantics. Doing the operations in JavaScript doubles leads to imprecision
and errors. That's why building with PRECISE_F32 makes it work.

The confusing thing is that LLVM only switches to exp2f when optimizing.
But that is correct as well, exp2f is power of 2, which is faster to
compute than a generic Math.pow(x, y) with arbitrary x. So this made the
bug harder to track down, but LLVM is also doing the right thing here.

Perhaps the only thing that is "wrong" is that emscripten does not have
PRECISE_F32 on by default. However, it increases code size by some 4% (on
bullet, which I tested now), and while its optimized well in firefox, it
still isn't in other browsers (box2d is almost 2x slower in chrome, 10%
slower in safari), so we should wait on them to improve before turning it
on by default.

However, an argument could be made that we should turn PRECISE_F32 on in
debug builds or -O0 or something like that, so -O0 is guaranteed to have
the right semantics. But I'm not sure that's the right thing either.
Thoughts?

- Alon


On Fri, Jan 30, 2015 at 6:40 AM, Stéphane Letz <[email protected]> wrote:

> So in other words the musl "exp2f" implementation seems incorrect yes? Is
> the following code used :
>
> https://github.com/rofl0r/musl/blob/master/src/math/exp2f.c
>
> Should we do a bug report?
>
> Or do you consider using musl "exp2f" in optimized mode in Emcripten is
> the problem in the first place?
>
> Thanks.
>
> Stéphane Letz
>
> Le jeudi 29 janvier 2015 21:03:00 UTC+1, Alon Zakai a écrit :
>>
>> Ok, that is very surprising, so I did more checking. It looks like your
>> original results were optimized? I tried without any optimization flags,
>> which leads to good results. But when I optimize, I see the same as you.
>>
>> What's going on is that when not optimizing, the emitted code uses
>> Math_pow. But when optimizing, LLVM emits an exp2f libc call. We implement
>> generic pow using Math.pow, but exp2f using the musl libc. And it turns out
>> that in musl exp2f, not having proper float32 precision leads to inaccuracy
>> that causes the bad results.
>>
>> In other words, we are running different code for pow when optimizing and
>> when not. This sort of makes sense, as I do see the musl methods as being
>> faster, but perhaps we should reconsider that? Regardless, when building
>> with PRECISE_F32=1 (not 0 or 2) there is a guarantee of proper float32
>> precision, and the results are as they should be.
>>
>> In this case here, which is best for your app depends on whether
>> performance or precision is most important. If you get decent speed with
>> your option 2, I would go with that (use your normal C code, build with
>> PRECISE_F32 support, but I would use 1 and not 2 in this case, as some
>> browsers will not have fround, and will get the bad results with option 2).
>>
>> - Alon
>>
>>
>>
>> On Wed, Jan 28, 2015 at 11:19 PM, Stéphane Letz <[email protected]> wrote:
>>
>>> Problem occurring on both Chrome 40.0.2214.93 (64-bit) and Firefox
>>> 35.0.1 on OSX 10.8.5.
>>>
>>> I wasn't aware of this PRECISE_F32 flag, thanks. But I'm a but confused
>>> here, the documentation says :
>>>
>>> ar PRECISE_F32 = 0; // 0: Use JS numbers for floating-point values.
>>> These are 64-bit and do not model C++
>>>
>>>                      //    floats exactly, which are 32-bit.
>>>
>>> Now if I use the following JS code instead of C in the first place, it
>>> works:
>>>
>>> midiToFreq = function (note)
>>>
>>> {
>>>
>>>     return 440.0 * Math.pow(2.0, (note - 69.0) / 12.0);
>>> }
>>>
>>> Then using -s PRECISE_F32=1 or -s PRECISE_F32=2 works, and I read
>>> that PRECISE_F32=2 is preferable. So now what is the best option:
>>>
>>> 1) just use the "double" midiToFreq version in the original C code and
>>> emcripten
>>>
>>> 2) or use the "float" version in the C original C code, emcripten
>>> and -s PRECISE_F32=2
>>>
>>> 3) to just avoid the C midiToFreq and use the pure JS midiToFreq version
>>> instead?
>>>
>>> Thanks.
>>>
>>> Stéphane
>>>
>>> Le jeudi 29 janvier 2015 00:30:32 UTC+1, Alon Zakai a écrit :
>>>>
>>>> Which platform and which JS engine is that?
>>>>
>>>> There are several possible issues here. The JS engine might be using
>>>> the system libc pow, but it might have it's own implementation (e.g. sin
>>>> and cos have been implemented in browsers), and different libcs and so
>>>> forth can be more or less precise. Also, since there are floats here,
>>>> building with -s PRECISE_F32=1 can make the results more like native. With
>>>> that I get almost identical results, but still some tiny rounding errors.
>>>> But even without it, the errors are much smaller than yours.
>>>>
>>>> - Alon
>>>>
>>>>
>>>>
>>>> On Wed, Jan 28, 2015 at 1:43 PM, Stéphane Letz <[email protected]> wrote:
>>>>
>>>>> The following code :
>>>>>
>>>>>
>>>>> double midiToFreq(double note)
>>>>>
>>>>> {
>>>>>
>>>>>     return 440.0 * pow(2.0, (note-69.0)/12.0);
>>>>>
>>>>> }
>>>>>
>>>>>
>>>>> float midiToFreq2(float note)
>>>>>
>>>>> {
>>>>>
>>>>>     return 440.0f * powf(2.0f, (note-69.0f)/12.0f);
>>>>>
>>>>> }
>>>>>
>>>>>
>>>>> int main()
>>>>>
>>>>> {
>>>>>
>>>>>     for (int i = 48; i < 84; i++) {
>>>>>
>>>>>         printf("pitch %d %f\n", i, midiToFreq(i));
>>>>>
>>>>>         printf("pitch %d %f\n", i, midiToFreq2(i));
>>>>>
>>>>>     }
>>>>>
>>>>> }
>>>>>
>>>>> correctly gives :
>>>>>
>>>>> pitch 48 130.812783
>>>>> pitch 48 130.812775
>>>>> pitch 49 138.591315
>>>>> pitch 49 138.591324
>>>>> pitch 50 146.832384
>>>>> pitch 50 146.832382
>>>>> pitch 51 155.563492
>>>>> pitch 51 155.563492
>>>>> pitch 52 164.813778
>>>>> pitch 52 164.813782
>>>>> pitch 53 174.614116
>>>>> ….
>>>>>
>>>>> when compiled with a C compiler and incorrectly gives the following
>>>>> when compiled with emcc and displayed in JS :
>>>>>
>>>>> pitch 48 130.812783
>>>>> pitch 48 130.812783
>>>>> pitch 49 138.591315
>>>>> pitch 49 136.604359
>>>>> pitch 50 146.832384
>>>>> pitch 50 148.968110
>>>>> pitch 51 155.563492
>>>>> pitch 51 155.563492
>>>>> pitch 52 164.813778
>>>>> pitch 52 162.450876
>>>>> pitch 53 174.614116
>>>>> pitch 53 177.153937
>>>>> pitch 54 184.997211
>>>>>
>>>>> When could be the reason for this strange behavior of the powf
>>>>> function ?
>>>>>
>>>>> Thanks.
>>>>>
>>>>> Stéphane Letz
>>>>>
>>>>>  --
>>>>> You received this message because you are subscribed to the Google
>>>>> Groups "emscripten-discuss" group.
>>>>> To unsubscribe from this group and stop receiving emails from it, send
>>>>> an email to [email protected].
>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>
>>>>
>>>>  --
>>> You received this message because you are subscribed to the Google
>>> Groups "emscripten-discuss" group.
>>> To unsubscribe from this group and stop receiving emails from it, send
>>> an email to [email protected].
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>>
>>  --
> You received this message because you are subscribed to the Google Groups
> "emscripten-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to