Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: pow(x, 2) different then x*x?

  1. #1
    Intern Contributor
    Join Date
    May 2013
    Posts
    69

    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.

    Code :
    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?

  2. #2
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    3,220
    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) = exp2 (x * log2 (y))

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

  3. #3
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    495
    Quote Originally Posted by Osbios View Post
    normalTex.x and normalTex.y are in the range -1..1
    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) + i*sin(x), and sin(n*π)=0 for any integer n). Using a different base just results in a factor of logbase(e) from logbase which is cancelled out by expbase.
    Quote Originally Posted by Osbios View Post
    Do I have a brain fart or can I point fingers at GPU drivers?
    .
    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.

  4. #4
    Intern Contributor
    Join Date
    May 2013
    Posts
    69
    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.

  5. #5
    Senior Member OpenGL Pro
    Join Date
    Jan 2007
    Posts
    1,215
    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.

  6. #6
    Member Regular Contributor
    Join Date
    Jun 2013
    Posts
    495
    Quote Originally Posted by Osbios View Post
    Also my first assumption was pow(x, 2) to be resolved as x * x.
    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).

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •