docs: public static double blackScholesOptionImpliedVolatility(
  			double forward,
  			double optionMaturity,
  			double optionStrike,
  			double payoffUnit,
  			double optionValue)
  	{
  		// Limit the maximum number of iterations, to ensure this calculation returns fast, e.g. in cases when there is no such thing as an implied vol
  		// TODO: An exception should be thrown, when there is no implied volatility for the given value.
  		int		maxIterations	= 500;
  		double	maxAccuracy		= 1E-15;
  
  		if(optionStrike <= 0.0)
  		{
  			// Actually it is not an option
  			return 0.0;
  		}
  		else
  		{
  			// Calculate an lower and upper bound for the volatility
  			double p = NormalDistribution.inverseCumulativeDistribution((optionValue/payoffUnit+optionStrike)/(forward+optionStrike)) / Math.sqrt(optionMaturity);
  			double q = 2.0 * Math.abs(Math.log(forward/optionStrike)) / optionMaturity;
  
  			double volatilityLowerBound = p + Math.sqrt(Math.max(p * p - q, 0.0));
  			double volatilityUpperBound = p + Math.sqrt(         p * p + q      );
  
  			// If strike is close to forward the two bounds are close to the analytic solution
  			if(Math.abs(volatilityLowerBound - volatilityUpperBound) < maxAccuracy) {
  				return (volatilityLowerBound+volatilityUpperBound) / 2.0;
  			}
  
  			// Solve for implied volatility
  			NewtonsMethod solver = new NewtonsMethod(0.5*(volatilityLowerBound+volatilityUpperBound) /* guess */);
  			while(solver.getAccuracy() > maxAccuracy && !solver.isDone() && solver.getNumberOfIterations() < maxIterations) {
  				double volatility = solver.getNextPoint();
  
  				// Calculate analytic value
  				double dPlus                = (Math.log(forward / optionStrike) + 0.5 * volatility * volatility * optionMaturity) / (volatility * Math.sqrt(optionMaturity));
  				double dMinus               = dPlus - volatility * Math.sqrt(optionMaturity);
  				double valueAnalytic		= (forward * NormalDistribution.cumulativeDistribution(dPlus) - optionStrike * NormalDistribution.cumulativeDistribution(dMinus)) * payoffUnit;
  				double derivativeAnalytic	= forward * Math.sqrt(optionMaturity) * Math.exp(-0.5*dPlus*dPlus) / Math.sqrt(2.0*Math.PI) * payoffUnit;
  
  				double error = valueAnalytic - optionValue;
  
  				solver.setValueAndDerivative(error,derivativeAnalytic);
  			}
  
  			return solver.getBestPoint();
  		}
  	}