How to work with half and snorm

I have just come across this article about half, snorm and unorm, but I don't get some of the points (or why they work).

1. According to the article, a half is basically a 16 bit float and an snorm is a signed float integer$^1$ dividied by 65535. Therefore, they are basically the same, just that the snorm is represented in $[-1, 1]$ whereas the half is in $[-65520; 65520)$ (where did those 32 values go?) but doesn't need another multiplication to get to the "real" value. Now the article says:

Other people prefer 16-bit xNORM variants because they tend to give really good precision and it is evenly distributed.

Why do they give a "good precision" and are "evenly distributed" (as opposed to the half)?

1. For snorm a division is suggested, by either $64$ or the maximum AABB value. I get the latter, that can be used for more or less any model then, but why use the magic number $64$ if I don't want to calculate it? Is it common to have models that don't exceed this specific value?

2. If I get good precision with half (or xnorm respectively) to save bandwidth, but in my application actually need really large position values, can I leverage the better precision of xnorm with a multiplication for "full" float and save myself from using double variables?

$^1$ Edit for future readers. I wrongly assumed it was a float.

• SNORMs and UNORMs are signed/unsigned integers divided by (2^M-1) Mar 6, 2018 at 13:48
• oh, I see. So all bits go directly into encoding the variable, rather than splitting it into exponent and mantissa, thus the (slightly) better precision?
– Tare
Mar 6, 2018 at 13:49
• Well, all the bits are used in floats too :-) Perhaps a better description is that range is more limited and that the precision throughout the range is uniform, rather than, as with floats, variable. FWIW colour channel data, e.g,. RGB888, uses 8-bit unorms. Mar 6, 2018 at 13:54

According to the article, a half is basically a 16 bit float and an snorm is a signed float dividied by 65535. Therefore, they are basically the same

No, they're not, and you do the article a great disservice by suggesting that it says such a thing.

Yes, Half-floats are 16-bit floats. But they are floating point numbers, as defined in IEEE-754. Which means that they can express a relatively large range of values.

Normalized integers can only directly express values in the range [0, 1] (for unsigned) and [-1, 1] (for signed). Floating-point numbers can extend beyond this range. 16-bit floats can express numbers approximately on the range [-6.55*104, 6.55*104], and it can handle decimal values in-between them.

Why do they give a "good precision" and are "evenly distributed" (as opposed to the half)?

Because that's how IEEE-754 works. After all, normalized 16-bit values and 16-bit float values have the same size. 16-bits of storage gives you 65536 different values, no matter how you interpret them. Therefore, to get the range of values outside of [-1, 1], 16-bit floats sacrifice some bits to define additional values.

16-bit floats give you about 3 decimal digits of precision. Normalized 16-bit values give you at most 5 (though the closer to zero you get, the fewer significant digits you get, unlike floating-point values).

why use the magic number 64 if I don't want to calculate it?

No reason; it's just a made-up number.

Is it common to have models that don't exceed this specific value?

Not particularly.

If I get good precision with half (or xnorm respectively) to save bandwidth, but in my application actually need really large position values, can I leverage the better precision of xnorm with a multiplication for "full" float and save myself from using double variables?

No.

Generally speaking, model space positions do not need "really large position values". They're in model space, so they're generally expressed relative to a center position that's quite close to them. They don't really have to be in scale with the rest of the world either.

However, if your model space positions really do need "really large position values", then you have to use whatever gives you the precision you need. That's pretty much never double.

• Nice answer but the part about 3 vs 5 digits of precision is misleading. It makes it sound as if a normalized integer is always better. Floating point has uniform relative precision while a normalized integer has uniform absolute precision. It just happens that the latter is what you want for model vertices. Mar 6, 2018 at 18:48
• I don't need really large position values, this was probably badly stated on my part. What I meant was models at "really large [i.e. far away from origin] positions in the world". Imagine a car simulator that spans more than 500km * 500km levels. For some reason I missinterpreted one of the articles sentence to say something about this. In any case, thanks for the answer, I'll edit the "disservice" question to mark it for future readers.
– Tare
Mar 7, 2018 at 6:47