In the fragment shader the texture2D returns a float per component with a range greater than [0.. 1.0].I do not think this complies with the OpenGL specification. Section 2.1.2 of the OpenGL ES 2.0 describes a conversion that gives a float component with the range [0..1.0]
The texel component values go through type and range conversions between definition in glTexImage2D and when they are used in the fragment shader. At glTexImage2D time the components are typically ubyte, [0..255]. In the fragment shader the texture2D returns a float per component with a range greater than [0.. 1.0]. When the color fragment is written to the destination surface there’s another type and range conversion back to [0..255] per component.
On lower precision hardware, if the fragment shader is doing arithmetic on the texture values, then the result could fall into a range that ends up with an unexpected 1 bit lsb difference after conversion to the framebuffer format.
A simplified description would be something like [0..0xFF] gets converted to the range [0..0x100] and back to [0..0xFF]. The intermediate range has ‘holes’ that lose on the conversion to the final range.