Pow(x, 2) different then x*x?

I have this two lines and they result in completely different results, and I don’t know why.

vec3 normal = vec3(normalTex.x, normalTex.y, sqrt(abs(normalTex.x * normalTex.x + normalTex.y * normalTex.y - 1.0f)));
vec3 normal = vec3(normalTex.x, normalTex.y, sqrt(abs(pow(normalTex.x, 2.0f) + pow(normalTex.y, 2.0f) - 1.0f)));

normalTex.x and normalTex.y are in the range -1…1

Do I have a brain fart or can I point fingers at GPU drivers?

If you look up pow(x,y) in the GLSL programming guide, you’ll see that its not defined where x < 0 (and also when x == 0 and y <= 0). The reason is that it is implemented as:

pow(x,y) = exp2 (y * log2 (x))

and the log isn’t defined for values <= 0.

Note that the GLSL 4.4 spec has a bug here; it says that pow() is actually implemented as:

pow(x,y) = [strike]exp2 (x * log2 (y))[/strike]

which (unless I need more caffeine this morning) is wrong.

The documentation for pow() says:

Results are undefined if x < 0.

In general, raising a negative value to a fractional power produces a complex result. There are specific cases where the imaginary part of the result is zero (e.g. if the fractional part of the exponent is zero, or the exponent is the reciprocal of an odd integer), but there isn’t a general algorithm which can handle these cases without involving complex numbers. In particular, implementing pow(x,y) as exp(log(x)*y) will result in a domain error from log() if x is negative and log() only understands real numbers.

With complex numbers, log() of a negative number will produce an complex number whose imaginary part is π, multiplying by an integer produces a complex number whose imaginary part is an integer multiple of π, and raising e to a complex number whose imaginary part is an integer multiple of π produces a real number (by Euler’s identity, eix = cos(x) + isin(x), and sin(nπ)=0 for any integer n). Using a different base just results in a factor of log[SUB]base/SUB from log[SUB]base[/SUB] which is cancelled out by exp[SUB]base[/SUB].

[QUOTE=Osbios;1255228]Do I have a brain fart or can I point fingers at GPU drivers? [/QUOTE].
The drivers aren’t at fault. And I doubt that The Powers That Be consider GLSL’s lack of support for complex numbers to be a bug per se.

More of a brain fart then, but to my defense the ref I looked up at the time didn’t mention this limitation. Also my first assumption was pow(x, 2) to be resolved as x * x.

Some compilers might resolve it that way, but it’s not guaranteed.

I’d be more inclined to write this as “dot (normalTex.xy, normalTex.xy)” anyway, which should optimize better.

The problem with that is that both arguments to pow() are floats (or vectors of floats), and interpreting exponentiation as “repeated multiplication” is only meaningful when the exponent is an integer.

In practical terms, that means “when the exponent is required to be an integer”, not “when it happens to be an integer”. Explicitly checking for integer exponents and selecting a different implementation would have a cost either in GPU cycles or in silicon.

If you want to calculate a square, use x*x. pow() is intended for the general case (e.g. specular exponent).

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.