# HLSL clamp infinity and nan to 0?

This topic is 2622 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

What's the best way to handle infinity and NaNs in shader code? It's cropped up a few times in the stuff I'm doing where I get either divides by 0, or 0/0, which produce +inf and nan, respectively.

In both cases my algorithm could handle it if I could set those values to 0. But I can't figure out a good way to do that.

Is there some function in HLSL that'll set a number to either itself or 0 if it's infinity or NaN?

##### Share on other sites
I'd also like to know.
For the time being, I'd just branch on [font="'Courier New"]isnan[/font]/[font="'Courier New"]isinf[/font]/[font="'Courier New"]isfinite[/font], although I'd be much happier if they returned a per-component result instead of a scalar...

##### Share on other sites
The best way is to avoid producing NaNs in the first place -- instead of checking that your result is NaN, check that your divisor is zero.

##### Share on other sites

The best way is to avoid producing NaNs in the first place -- instead of checking that your result is NaN, check that your divisor is zero.

It's not always easy if you're trying to avoid branches. Lots of numerical algorithms are "do A unless B then do C instead". If you can robustly wrap up all the logic into a single code path regardless of wonky input you often get wins (performance and/or code size).

...

Anyway, this seems to work on my machine (it's hard to get a definite test going). I'm not sure definitively if this is defined behavior or not, though.

 A = step(A, A) * A; 

'A' can be a scalar, vector, or matrix. It works on NaNs on the assumption that they won't be >= to themselves. I'm not sure why it'd work on infinities but it does seem to.

Here's the exact test I'm running:
 float x = 0; float y = 0; float2 vec = float2(x/y, 1/x); vec = step(vec, vec) * vec; CheckEqual(float2(0,0), vec); 

Where CheckEqual sets some colors up for output. It's possible the compiler is doing some magic stuff behind my back, and that it wouldn't work in a production environment. I haven't looked at the produced assembly.

##### Share on other sites
Which shader model are you targeting BTW?
I was thinking of something like: float2 inputs = float2(0, 0); float2 vec = lerp( saneValues, inputs, abs(sign(inputs)) ); float2 vec = float2(inputs.x/inputs.y, 1/inputs.x);But without knowing the problem being solved, I don't know how appropriate this is

I just tested Krohm's suggestion out too, and it does compile to a conditional move (no branches). vec.x = isinf(vec.x) ? 0 : vec.x; vec.y = isinf(vec.y) ? 0 : vec.y;
Anyway, this seems to work on my machine (it's hard to get a definite test going). I'm not sure definitively if this is defined behavior or not, though.A = step(A, A) * A;[/quote]Interesting solution! It seems a bit strange though -- both [font="Courier New"]0*inf[/font] and [font="Courier New"]0*NaN[/font] should result in [font="Courier New"]NaN[/font], according to the IEEE standard. Pretty much any operation where one operand is [font="Courier New"]NaN[/font] will produce another [font="Courier New"]NaN[/font], and most operations where one operand is [font="Courier New"]inf[/font] will produce either [font="Courier New"]inf[/font] or [font="Courier New"]NaN[/font]. The fact that you're getting a 0 out of it shows that the GPU isn't following the IEEE spec properly. FXC has the [font="'Courier New"]/Gis[/font] switch to force strict IEEE compliance -- does this affect the result?

##### Share on other sites
This might be an odd solution but I just add an epsilon like 0.0001 to my vectors. Always annoyed me that GPU designers didn't just make x/0 equal to zero. It's a trick that comes up a lot when trying to get rid of branches I'd imagine. (That is x/(x + 0.00001) will return 0 or 1 essentially to be used with lerp and other crazy stuff).

Anyone else do this or am I insane?

##### Share on other sites

Which shader model are you targeting BTW?

2 or 3. Probably 3 just for instruction count issues (it's a monolithic shader).

Interesting solution! It seems a bit strange though -- both [font="Courier New"]0*inf[/font] and [font="Courier New"]0*NaN[/font] should result in [font="Courier New"]NaN[/font], according to the IEEE standard. Pretty much any operation where one operand is [font="Courier New"]NaN[/font] will produce another [font="Courier New"]NaN[/font], and most operations where one operand is [font="Courier New"]inf[/font] will produce either [font="Courier New"]inf[/font] or [font="Courier New"]NaN[/font]. The fact that you're getting a 0 out of it shows that the GPU isn't following the IEEE spec properly.
[/quote]

Oh, haha. Funny thing is I should have remembered 0*inf and 0*NaN produce NaNs, as I've hit it enough on the CPU side. I'm just so used to using 'step' as a ternary operator.

So yeah, no idea why it works at all then, or if it's cross platform at all.

FXC has the [font="Courier New"]/Gis[/font] switch to force strict IEEE compliance -- does this affect the result?
[/quote]

FX Composer? I used it for a bit but anymore I switched over to a special unit testing harness I built for HLSL, which feeds things through the XNA HLSL compiler. I'm not sure if it has those sorts of options to tweak.

##### Share on other sites

This might be an odd solution but I just add an epsilon like 0.0001 to my vectors. Always annoyed me that GPU designers didn't just make x/0 equal to zero. It's a trick that comes up a lot when trying to get rid of branches I'd imagine. (That is x/(x + 0.00001) will return 0 or 1 essentially to be used with lerp and other crazy stuff).

Anyone else do this or am I insane?

I was trying to avoid epsilons where I could. It always feels like a bad hack for shader code.

##### Share on other sites
FXC has the [font="Courier New"]/Gis[/font] switch to force strict IEEE compliance -- does this affect the result?
FX Composer? I switched over to the XNA HLSL compiler. I'm not sure if it has those sorts of options to tweak.[/quote]fxc.exe is the D3D offline shader compiler. I haven't used any XNA tools, but I'd hope that they expose the underlying options
Anyone else do this or am I insane?
Yeah, I add epsillons to the divisor a lot of places where it's at risk of becomming zero, but 'near zero' still provides a valid result. IIRC, IEEE-float was designed so that in some circumstances you can use specific epsilon values for some purposes like this without adversely affecting 'good' values at all.

##### Share on other sites
I haven't used any XNA tools, but I'd hope that they expose the underlying options

You'd hope, but you'd be wrong.

1. 1
Rutin
42
2. 2
3. 3
4. 4
5. 5

• 9
• 27
• 20
• 14
• 14
• ### Forum Statistics

• Total Topics
633385
• Total Posts
3011605
• ### Who's Online (See full list)

There are no registered users currently online

×