class BlackFormulaRepository {

  @ExternalFunction
  public static double thetaMod(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol, final boolean isCall, final double interestRate) {
    ArgumentChecker.isTrue(forward >= 0.0, "negative/NaN forward; have {}", forward);
    ArgumentChecker.isTrue(strike >= 0.0, "negative/NaN strike; have {}", strike);
    ArgumentChecker.isTrue(timeToExpiry >= 0.0, "negative/NaN timeToExpiry; have {}", timeToExpiry);
    ArgumentChecker.isTrue(lognormalVol >= 0.0, "negative/NaN lognormalVol; have {}", lognormalVol);
    ArgumentChecker.isFalse(Double.isNaN(interestRate), "interestRate is NaN");

    if (-interestRate > LARGE) {
      return 0.;
    }
    final double driftLess = driftlessTheta(forward, strike, timeToExpiry, lognormalVol);
    if (Math.abs(interestRate) < SMALL) {
      return driftLess;
    }

    final double rootT = Math.sqrt(timeToExpiry);
    double sigmaRootT = lognormalVol * rootT;
    if (Double.isNaN(sigmaRootT)) {
      s_logger.info("lognormalVol * Math.sqrt(timeToExpiry) ambiguous");
      sigmaRootT = 1.;
    }
    final int sign = isCall ? 1 : -1;

    final boolean bFwd = (forward > LARGE);
    final boolean bStr = (strike > LARGE);
    final boolean bSigRt = (sigmaRootT > LARGE);
    double d2 = 0.;

    double priceLike = Double.NaN;
    final double rt = (timeToExpiry < SMALL && Math.abs(interestRate) > LARGE) ? (interestRate > 0. ? 1. : -1.)
        : interestRate * timeToExpiry;
    if (bFwd && bStr) {
      s_logger.info("(large value)/(large value) ambiguous");
      priceLike = isCall ? 0. : (strike >= forward ? strike : 0.);
    } else {
      if (sigmaRootT < SMALL) {
        if (rt > LARGE) {
          priceLike = 0.;
        } else {
          priceLike = isCall ? (forward > strike ? -strike : 0.0) : (forward > strike ? 0.0 : +strike);
        }
      } else {
        if (Math.abs(forward - strike) < SMALL | bSigRt) {
          d2 = -0.5 * sigmaRootT;
        } else {
          d2 = Math.log(forward / strike) / sigmaRootT - 0.5 * sigmaRootT;
        }
        final double nS = NORMAL.getCDF(sign * d2);
        priceLike = (nS == 0.) ? 0. : -sign * strike * nS;
      }
    }

    final double res = (interestRate > LARGE && Math.abs(priceLike) < SMALL) ? 0. : interestRate * priceLike;
    return Math.abs(res) > LARGE ? res : driftLess + res;
  }

}