docs: public static double sabrBerestyckiNormalVolatilityApproximation(double alpha, double beta, double rho, double nu, double displacement, double underlying, double strike, double maturity)
  	{
  		// Apply displacement. Displaced model is just a shift on underlying and strike.
  		underlying += displacement;
  		strike += displacement;
  
  		double forwardStrikeAverage = (underlying+strike) / 2.0;		// Original paper uses a geometric average here
  
  		double z;
  		if(beta < 1.0) {
  			z = nu / alpha * (Math.pow(underlying, 1.0-beta) - Math.pow(strike, 1.0-beta)) / (1.0-beta);
  		} else {
  			z = nu / alpha * Math.log(underlying/strike);
  		}
  
  		double x = Math.log((Math.sqrt(1.0 - 2.0*rho*z + z*z) + z - rho) / (1.0-rho));
  
  		double term1;
  		if(Math.abs(underlying - strike) < 1E-10 * (1+Math.abs(underlying))) {
  			// ATM case - we assume underlying = strike
  			term1 = alpha * Math.pow(underlying, beta);
  		}
  		else {
  			term1 = nu * (underlying-strike) / x;
  		}
  		double sigma = term1 * (1.0 + maturity * ((-beta*(2-beta)*alpha*alpha)/(24*Math.pow(forwardStrikeAverage,2.0*(1.0-beta))) + beta*alpha*rho*nu / (4*Math.pow(forwardStrikeAverage,(1.0-beta))) + (2.0 -3.0*rho*rho)*nu*nu/24));
  
  		return Math.max(sigma, 0.0);
  	}