What does the constant 0.0039215689 represent?
Solution 1
0.0039215689
is approximately equal to 1/255
.
Seeing that this is OpenGL, performance is probably important. So it's probably safe to guess that this was done for performance reasons.
Multiplying by the reciprocal is faster than repeatedly dividing by 255.
Side Note:
If you're wondering why such a micro-optimization isn't left to the compiler, it's because it is an unsafe floating-point optimization. In other words:
x / 255 != x * (1. / 255)
due to floating-point round-off errors.
So while modern compilers may be smart enough to do this optimization, they are not allowed to do it unless you explicitly tell them to via a compiler flag.
Related: Why doesn't GCC optimize a*a*a*a*a*a to (a*a*a)*(a*a*a)?
Solution 2
This multiplication by 0.0039215689f
converts an integer valued color intensity in the range 0 to 255 to a real valued color intensity in the range 0 to 1.
As Ilmari Karonen points out, even if this is an optimisation it's a rather badly expressed one. It would be so much clearer to multiply by (1.0f/255)
.
crush
Programming since I was 13 years old. Everyday, try to learn something new. Everyday, learning just how little I know. All views expressed here are my own, and not those of my employer. Languages & Technologies: C++, C#, ASP.NET, Java, JavaScript, JSON, PHP, XML, CSS, HTML, SQL. Dabbled in more than I could name. Official developer for the Star Wars Galaxies Emulator project since 2006. Topics on Meta that I condone: Please, be nice to new users Using KBD for anything but defining a keyboard sequence is abuse. Code only answers only tell the how, and not the why.
Updated on April 11, 2020Comments
-
crush about 4 years
I keep seeing this constant pop up in various graphics header files
0.0039215689
It seems to have something to do with color maybe?
Here is the first hit on Google:
void RDP_G_SETFOGCOLOR(void) { Gfx.FogColor.R = _SHIFTR(w1, 24, 8) * 0.0039215689f; Gfx.FogColor.G = _SHIFTR(w1, 16, 8) * 0.0039215689f; Gfx.FogColor.B = _SHIFTR(w1, 8, 8) * 0.0039215689f; Gfx.FogColor.A = _SHIFTR(w1, 0, 8) * 0.0039215689f; } void RDP_G_SETBLENDCOLOR(void) { Gfx.BlendColor.R = _SHIFTR(w1, 24, 8) * 0.0039215689f; Gfx.BlendColor.G = _SHIFTR(w1, 16, 8) * 0.0039215689f; Gfx.BlendColor.B = _SHIFTR(w1, 8, 8) * 0.0039215689f; Gfx.BlendColor.A = _SHIFTR(w1, 0, 8) * 0.0039215689f; if(OpenGL.Ext_FragmentProgram && (System.Options & BRDP_COMBINER)) { glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, Gfx.BlendColor.R, Gfx.BlendColor.G, Gfx.BlendColor.B, Gfx.BlendColor.A); } } //...more like this
What does this number represent? Why does no one seem to declare it as a const?
I couldn't find anything on Google that explained it.
-
xav about 10 yearsNote: Color components (e.g. red, green, blue, alpha) are often represented as an integer in [0 ; 255] in many APIs
-
M.M about 10 yearsIs there any reason the source code would write this instead of
(1.f/255)
? -
Navin about 10 years@MattMcNabb Maybe they are hoping it will not be evaluated in extended precision.
-
Paul Draper about 10 yearsMmmm...if only there were some way to avoid magic numbers....
-
jfs about 10 years
1/255 == 0.00(3921568627450980)
-- parens mean repetition. -
AakashM about 10 yearsWith your next magic number, try asking Wolfram Alpha
-
crush about 10 years@AakashM Awesome. Thanks for that. That's really neat.
-
Jeppe Stig Nielsen about 10 years@J.F.Sebastian Note, that in base-256, the expansion will clearly be
{00}.{01}{01}{01}{01}...
where{01}
is the single digit "one" in base-256. So in binary it will be0.(00000001)
where the parens mean repetition. -
jfs about 10 years@JeppeStigNielsen: in base-256, it is:
0.(1)
(1
is a more traditional representation of "one" than{01}
) -
Isaac Rabinovitch about 10 yearswhatever the reason, using a magic number without documenting its purpose is very uncool
-
crush about 10 years@LionC I don't agree with the latest edit on this question. While it can be argued that the question itself has nothing to do with
C
, it has very much to do withfloating-point
. -
LionC about 10 years@crush Youre probably right, seems I brainfarted there ;-) thx
-
Sandburg over 5 years
C
dev have reflexes... optimizing at the place of the compiler. Why is it the first version? Have a problem, then solve it. -
Luis Colorado over 5 years@IsaacRabinovitch, I'm afraid I have received complaints about overcommenting things in code.... there are tastes for everything... but I'm with you.
-
-
crush about 10 yearsWow. All I can say is awesome answer. I probably would never have discovered this without your knowledge. Of course, now knowing what it represents, it seems quite obvious!
-
Mysticial about 10 yearsI actually didn't know what it was when I first saw it. But seeing the way it was used, I suspected it was the multiply-by-reciprocal optimization. So I checked in my calculator and sure enough - I guessed right.
-
Adrian McCarthy about 10 yearsFascinating. I suppose, on a modern processor, multiplication can be faster than a look-up table. Then again, I'd expect a conversion from an 8-bit color channel to float would want a gamma correction (or even an sRGB to linear conversion), in which case a look-up table is probably a win.
-
Ilmari Karonen about 10 yearsI would've expected to see it written as
a = b * (1.0f / 255)
; compilers still do constant folding, don't they? -
Mysticial about 10 years@IlmariKaronen Yes, they still do constant folding. It's actually required for some stuff like template resolutions and such. But I would've just pulled it out as a constant or a macro. But hey, not all code is perfectly written. :)
-
Bohemian about 10 yearsstrict floating point adherence... isn't that what the
strictfp
keyword is for (if you need it)? -
Mysticial about 10 years@Bohemian IIRC, the standard allows some leeway in that intermediate results of a floating-point expression can be done at higher precision.
strictfp
turns that off. But to do unsafe floating-point optimizations that require associativity (such as this), you need to tell the compiler to do it. (In GCC, it would be-ffast-math
.) -
Pascal Cuoq about 10 years@Bohemian
strictfp
is not part of the C standard. It exists in Java but one should not mix discussions of Java and C with regard to floating-point, they are each complex enough on their own (and quite different). -
hippietrail about 10 yearsIt seems strange to me that such things would be using a scale of 255 rather than 256. Am I missing something?
-
Mysticial about 10 years@hippietrail Initially, I was wondering the same thing. But if you use 256, it would scale from
0.0 - 0.996
instead the desired0.0 - 1.0
. (0.996 = 255/256
where255
is the largest 8-bit integer) -
Johny about 10 yearsOr maybe better, defined as constant?
-
David Heffernan about 10 years@Johny Certainly defined as a constant. The point being not a magic value.
-
Jeffrey about 10 yearsAn interesting question could be - why not 0.0039215686 or 0.0039215687, which are closer approximations at the same level of precision?
-
Jeffrey about 10 yearsAnd of course, to answer my own question, it's because the other two numbers can not be represented as standard C floats. The next float below 0.0039215689 is 0.0039215684.
-
dan04 about 10 yearsTo be precise, the closest IEEE single-precision floating-point number to 1/255 is 0.0039215688593685626983642578125.
-
Jack Aidley about 10 yearsOf course, a better programmer writing the header file would have defined a constant and used it by name.
-
crush about 10 years@JackAidley That's the odd thing. I couldn't find a single example online where a programmer defined a constant, yet, this magic number seems to be in widespread use. I actually first encountered it while disassembling an executable that was written in C++. Since then, I've been unable to find a single instance where it's defined as a constant...it might be that it's part of some standard graphics library.
-
Z boson about 10 yearsIt's maybe worth pointing out that there is a similar trick for integers to multiply a reciprocal rather than divide using magic numbers. For example n/255 = (0x80808081*n)>>39.
-
Rakshith Ravi over 8 years@Mysticial Wait...why is it faster to multiply by the reciprocal than divide by 255?
-
Mysticial over 8 years@RakshithRavi Because division is slower than multiplication.
-
Rakshith Ravi over 8 years@Mysticial yeah but why?
-
Mysticial over 8 years@RakshithRavi stackoverflow.com/questions/15745819/…