tanh of Unity shader does not work with a large argument,

The tanh() function of shaderlab does not work with a large argument, such as 100.

My environment is Unity 2017.2.03f (WIndows 64bit).

Here is minimum sample code using vertex shader in order to shift an object.

Shader "Custom/tanh_test" {
	Properties{
		_MainTex("Texture", 2D) = "white" {}
		_Value("Value", float) = 1.0
	}

	SubShader {
		Tags {
			"RenderType" = "Opaque"
			"Queue" = "Background"
		}

		CGPROGRAM

		#pragma surface surf Lambert vertex:vert addshadow
		#pragma target 5.0
		#include "UnityCG.cginc"

		struct Input {
			float2 uv_MainTex;
		};
		sampler2D _MainTex;
		float _Value;

		void vert(inout appdata_full v) {
			v.vertex.z = v.vertex.z + tanh(_Value);
		}

		void surf(Input IN, inout SurfaceOutput o) {
			o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
		}

		ENDCG
	}
	Fallback "Diffuse"
}

If the “_Value” becoms large like 100, the tanh(_Value) returns zero.
Is this bug of Unity ??

Thanks for your answers.

Value is not fixed in my development, and want to change from around 1 to 250.

I use “if” state for checking the returned value becomes zero.

if (tanh(_Value) == 0) {
// do something
}

Well, indeed tanh seems to be only defined within some arbitrary range of about (± 174.6733) after which it returns 0. This is probably due to the fact how tanh is implemented. The usual reference implementation is this:

float tanh(float x)
{
  float exp2x = exp(2*x);
  return (exp2x - 1) / (exp2x + 1);
}

However the problem is that exp(2* 174) is around the limit of double floating point range. That means that the expression would turn in either huge / +inf which is 0 or (+inf / +inf) which is NaN (probably fixed to 0).

Does it have to be tanh? Usually it’s simpler to use x/(1+abs(x)) which has a similar distribution but doesn’t grow so fast. Look at those two images:

Here’s the same at a scale of 100

The shader i used simply does this:

fixed4 frag (v2f i) : SV_Target
{
    float v = _Factor * i.worldPos.x;
    if (i.worldPos.y > 0)
        v = tanh(v);
    else
        v = v / (1+abs(v));
    fixed4 col = fixed4(v,-v,0,1);
    return col;
}