Devblog: Fixed point vs floating point

I had an interesting problem with one of the sites I tried loading a while ago. was using jQuery (version 1.7.2) which tries to detect browser features, and decided Flow was actually Internet Explorer. It later tried to use IE-specific filters rather than CSS opacity, so no fades worked. I tracked this down to jQuery’s startup code setting opacity to 0.55 and then getting it back out again. Since we converted 0.55 into 16.16 fixed point too early, it was retrieving it as 0.549988. That wasn’t equal to 0.55, and so jQuery decided Flow didn’t support opacity and therefore must be Internet Explorer.

Browsers use fixed point maths internally for storing the results of many calculations. Often 26.6 bits, which gives 64 positions between (CSS) pixels, or 24.8 bits to give 256 levels of anti-aliasing in graphics.

Our initial design for CSS style tried to use the most applicable value possible, so for the width property we would store the parsed value as 26.6 precision but SVG values would often use 16.16 precision (the SVG Tiny 1.2 spec suggests this).

This made sense when we were targeting CPUs without floating point with our SVG Engine, but nowadays everything that is expected to run in a modern browser has hardware floating point support – especially if they come with OpenGL ES. Various web platform tests check the calculated results of properties in ways that require us to store them using floating point – at the very least, it’s a reasonable assumption to expect that getting a value from JavaScript would return the value you set in the first place.

Switching to floats, instead of storing values in three different precisions, simplified most of our style getters and removed lots of legacy code. For a few properties, it may be trivially slower, but the precision gains for compatibility with JavaScript libraries, meant it was necessary and probably sensible anyway.

Different sites and JavaScript libraries use many different methods for browser detection. This version of jQuery is pretty ancient, but it’s a useful demonstration of incorrect assumptions that can be made from one function call that can cause strange behaviour later.

If you’d like to automatically receive our posts by email please join our mailing list.