Example usage for com.google.common.math DoubleMath fuzzyEquals

List of usage examples for com.google.common.math DoubleMath fuzzyEquals

Introduction

In this page you can find the example usage for com.google.common.math DoubleMath fuzzyEquals.

Prototype

public static boolean fuzzyEquals(double a, double b, double tolerance) 

Source Link

Document

Returns true if a and b are within tolerance of each other.

Usage

From source file:com.analog.lyric.collect.ArrayUtil.java

/**
 * True if all values in {@code array} are {@link DoubleMath#fuzzyEquals}
 * to each other with given {@code tolerance}. Returns true for arrays
 * of less than length 2.//from   w  w w.j a  va 2s.com
 * 
 * @see #subsetFuzzyEqual(double[], int[], double)
 */
public static boolean allFuzzyEqual(double[] array, double tolerance) {
    if (array.length > 1) {
        double min, max;
        min = max = array[0];

        for (int i = 1, end = array.length; i < end; ++i) {
            final double d = array[i];
            min = Math.min(min, d);
            max = Math.max(max, d);
        }
        if (!DoubleMath.fuzzyEquals(min, max, tolerance)) {
            return false;
        }
    }

    return true;
}

From source file:com.opengamma.strata.pricer.impl.volatility.smile.function.SabrHaganVolatilityFunctionProvider.java

@Override
public double getVolatility(double forward, double strike, double timeToExpiry, SabrFormulaData data) {
    ArgChecker.isTrue(forward > 0.0, "forward must be greater than zero");
    ArgChecker.isTrue(strike >= 0.0, "strike must be greater than zero");
    ArgChecker.isTrue(timeToExpiry >= 0.0, "timeToExpiry must be greater than zero");
    ArgChecker.notNull(data, "data");

    double alpha = data.getAlpha();
    double beta = data.getBeta();
    double rho = data.getRho();
    double nu = data.getNu();
    if (alpha == 0.0) {
        return 0.0;
    }/*from   w ww.  j  a v a  2 s .c om*/
    double cutoff = forward * CUTOFF_MONEYNESS;
    double k;
    if (strike < cutoff) {
        Logger s_logger = LoggerFactory.getLogger(SabrHaganVolatilityFunctionProvider.class);
        s_logger.info("Given strike of {} is less than cutoff at {}, therefore the strike is taken as {}",
                new Object[] { strike, cutoff, cutoff });
        k = cutoff;
    } else {
        k = strike;
    }
    double vol, z, zOverChi;
    double beta1 = 1 - beta;
    if (DoubleMath.fuzzyEquals(forward, k, ATM_EPS)) {
        double f1 = Math.pow(forward, beta1);
        vol = alpha * (1 + timeToExpiry * (beta1 * beta1 * alpha * alpha / 24 / f1 / f1
                + rho * alpha * beta * nu / 4 / f1 + nu * nu * (2 - 3 * rho * rho) / 24)) / f1;
    } else {
        if (DoubleMath.fuzzyEquals(beta, 0, BETA_EPS)) {
            double ln = Math.log(forward / k);
            z = nu * Math.sqrt(forward * k) * ln / alpha;
            zOverChi = getZOverChi(rho, z);
            vol = alpha * ln * zOverChi
                    * (1 + timeToExpiry * (alpha * alpha / forward / k + nu * nu * (2 - 3 * rho * rho)) / 24)
                    / (forward - k);
        } else if (DoubleMath.fuzzyEquals(beta, 1, BETA_EPS)) {
            double ln = Math.log(forward / k);
            z = nu * ln / alpha;
            zOverChi = getZOverChi(rho, z);
            vol = alpha * zOverChi
                    * (1 + timeToExpiry * (rho * alpha * nu / 4 + nu * nu * (2 - 3 * rho * rho) / 24));
        } else {
            double ln = Math.log(forward / k);
            double f1 = Math.pow(forward * k, beta1);
            double f1Sqrt = Math.sqrt(f1);
            double lnBetaSq = Math.pow(beta1 * ln, 2);
            z = nu * f1Sqrt * ln / alpha;
            zOverChi = getZOverChi(rho, z);
            double first = alpha / (f1Sqrt * (1 + lnBetaSq / 24 + lnBetaSq * lnBetaSq / 1920));
            double second = zOverChi;
            double third = 1 + timeToExpiry * (beta1 * beta1 * alpha * alpha / 24 / f1
                    + rho * nu * beta * alpha / 4 / f1Sqrt + nu * nu * (2 - 3 * rho * rho) / 24);
            vol = first * second * third;
        }
    }
    //There is nothing to prevent the nu * nu * (2 - 3 * rho * rho) / 24 part taking the third term, and hence the volatility negative
    return vol;
    // return Math.max(0.0, vol);
}

From source file:dk.dma.dmiweather.grib.AbstractDataProvider.java

@Override
public float[] getData(GeoCoordinate northWest, GeoCoordinate southEast, int Nx, int Ny, double lonSpacing,
        double latSpacing) {

    validate(northWest, southEast);//  w w w. j  a  v a2 s  . c  o  m

    int startY = (int) Math.round((southEast.getLat() - this.la1) / this.dy);
    int startX = (int) Math.round((northWest.getLon() - this.lo1) / this.dx);

    float[] grid = new float[Ny * Nx];

    double tolerance = 0.00001;
    if (DoubleMath.fuzzyEquals(this.dx, lonSpacing, tolerance)
            && DoubleMath.fuzzyEquals(this.dy, latSpacing, tolerance)) {
        // native resolution
        float[] data = roundAndCache();
        for (int row = 0; row < Ny; row++) {
            System.arraycopy(data, (startY + row) * this.Nx + startX, grid, row * Nx, Nx);
        }
    } else {
        if (Nx > this.Nx && Ny < this.Ny || Ny > this.Ny && Nx < this.Nx) {
            throw new APIException(ErrorMessage.INVALID_SCALING,
                    String.format("Native Nx:%s, Ny:%s, desired Nx:%s, Ny:%s", this.Nx, this.Ny, Nx, Ny));
        }

        if (Nx > this.Nx) {
            // scaling up
            float[] data = roundAndCache();
            for (int row = 0; row < Ny; row++) {
                int y = startY + (int) Math.round(Math.floor(row * latSpacing));
                for (int col = 0; col < Nx; col++) {
                    int x = startX + (int) Math.round(Math.floor(col * lonSpacing));

                    float datum = data[y * this.Nx + x];
                    grid[row * Nx + col] = datum;
                }
            }

        } else {

            float[] data = roundAndCache();

            for (int row = 0; row < Ny; row++) {
                int y = startY + (int) Math.round(row * latSpacing / this.dy);
                for (int col = 0; col < Nx; col++) {

                    int x = startX + (int) Math.round(col * lonSpacing / this.dx);
                    float datum = data[y * this.Nx + x];

                    if (datum == GRIB_NOT_DEFINED) {
                        // when we down-sample we may end up selecting only NOT_DEFINED, so we look around to see if there is a defined value close by
                        int xSearchDistance = (int) Math.round(lonSpacing / 2);
                        int ySearchDistance = (int) Math.round(latSpacing / 2); // we search the space between points

                        float[] candidate = new float[] { this.Nx + this.Ny, GRIB_NOT_DEFINED }; // to hold the closest distance and the value

                        searchRow(data, y, x, xSearchDistance, candidate); // search this row

                        for (int i = 1; i <= ySearchDistance && i < candidate[0]; i++) {
                            if (y - i > 0) {
                                // there is a row before
                                searchRow(data, y - i, x, xSearchDistance, candidate);
                            } else if (y + i < this.Ny) {
                                //there is a row after
                                searchRow(data, y + i, x, xSearchDistance, candidate);
                            } else {
                                break;
                            }
                        }
                        datum = candidate[1];
                    }

                    grid[row * Nx + col] = datum;
                }
            }
        }
    }

    return grid;
}

From source file:org.objectweb.proactive.extensions.p2p.structured.overlay.can.zone.Zone.java

/**
 * Indicates whether the specified {@code zone} can be merged with the
 * current zone that abuts on the given {@code neighborDimension}.
 * //from  www  .j  a  v a2s.c  o m
 * @param zone
 *            the zone to check with.
 * 
 * @param neighborDimension
 *            the dimension on which the the given zone neighbor the current
 *            one.
 * 
 * @return {@code true} if the specified zone can merged with the current
 *         one, {@code false} otherwise.
 */
@SuppressWarnings("unchecked")
public boolean canMerge(Zone<E> zone, byte neighborDimension) {
    Zone<E> currentZoneCopy = null;
    try {
        currentZoneCopy = (Zone<E>) MakeDeepCopy.makeDeepCopy(this);

        currentZoneCopy.lowerBound.setCoordinate(neighborDimension, Coordinate
                .min(this.lowerBound.getCoordinate(neighborDimension), zone.getLowerBound(neighborDimension)));

        currentZoneCopy.upperBound.setCoordinate(neighborDimension, Coordinate
                .max(this.upperBound.getCoordinate(neighborDimension), zone.getUpperBound(neighborDimension)));

        return DoubleMath.fuzzyEquals(currentZoneCopy.getArea(), this.getArea() + zone.getArea(), 0.00001);
    } catch (ClassNotFoundException e) {
        throw new IllegalStateException(e);
    } catch (IOException e) {
        throw new IllegalStateException(e);
    }
}

From source file:com.opengamma.strata.pricer.impl.volatility.smile.SabrHaganVolatilityFunctionProvider.java

@Override
public double volatility(double forward, double strike, double timeToExpiry, double alpha, double beta,
        double rho, double nu) {

    ArgChecker.isTrue(forward > 0.0, "forward must be greater than zero");
    ArgChecker.isTrue(strike >= 0.0, "strike must be greater than zero");
    ArgChecker.isTrue(timeToExpiry >= 0.0, "timeToExpiry must be greater than zero");

    if (alpha == 0.0) {
        return 0.0;
    }//from  w w  w .j av a 2  s.  com
    double cutoff = forward * CUTOFF_MONEYNESS;
    double k;
    if (strike < cutoff) {
        Logger s_logger = LoggerFactory.getLogger(SabrHaganVolatilityFunctionProvider.class);
        s_logger.info("Given strike of {} is less than cutoff at {}, therefore the strike is taken as {}",
                new Object[] { strike, cutoff, cutoff });
        k = cutoff;
    } else {
        k = strike;
    }
    double vol, z, zOverChi;
    double beta1 = 1 - beta;
    if (DoubleMath.fuzzyEquals(forward, k, ATM_EPS)) {
        double f1 = Math.pow(forward, beta1);
        vol = alpha * (1 + timeToExpiry * (beta1 * beta1 * alpha * alpha / 24 / f1 / f1
                + rho * alpha * beta * nu / 4 / f1 + nu * nu * (2 - 3 * rho * rho) / 24)) / f1;
    } else {
        if (DoubleMath.fuzzyEquals(beta, 0, BETA_EPS)) {
            double ln = Math.log(forward / k);
            z = nu * Math.sqrt(forward * k) * ln / alpha;
            zOverChi = getZOverChi(rho, z);
            vol = alpha * ln * zOverChi
                    * (1 + timeToExpiry * (alpha * alpha / forward / k + nu * nu * (2 - 3 * rho * rho)) / 24)
                    / (forward - k);
        } else if (DoubleMath.fuzzyEquals(beta, 1, BETA_EPS)) {
            double ln = Math.log(forward / k);
            z = nu * ln / alpha;
            zOverChi = getZOverChi(rho, z);
            vol = alpha * zOverChi
                    * (1 + timeToExpiry * (rho * alpha * nu / 4 + nu * nu * (2 - 3 * rho * rho) / 24));
        } else {
            double ln = Math.log(forward / k);
            double f1 = Math.pow(forward * k, beta1);
            double f1Sqrt = Math.sqrt(f1);
            double lnBetaSq = Math.pow(beta1 * ln, 2);
            z = nu * f1Sqrt * ln / alpha;
            zOverChi = getZOverChi(rho, z);
            double first = alpha / (f1Sqrt * (1 + lnBetaSq / 24 + lnBetaSq * lnBetaSq / 1920));
            double second = zOverChi;
            double third = 1 + timeToExpiry * (beta1 * beta1 * alpha * alpha / 24 / f1
                    + rho * nu * beta * alpha / 4 / f1Sqrt + nu * nu * (2 - 3 * rho * rho) / 24);
            vol = first * second * third;
        }
    }
    //There is nothing to prevent the nu * nu * (2 - 3 * rho * rho) / 24 to be large negative, and hence the volatility negative
    return Math.max(MIN_VOL, vol);
}

From source file:com.datascience.gal.AbstractDawidSkene.java

public AbstractDawidSkene(String id, Collection<Category> categories) {
    this(id);//from  w w  w  .j ava2  s  . c  om
    this.fixedPriors = false;
    this.categories = new HashMap<String, Category>();
    double priorSum = 0.;
    int priorCnt = 0;

    if (categories.size() < 2) {
        throw new IllegalArgumentException("There should be at least two categories");
    }
    for (Category c : categories) {
        this.categories.put(c.getName(), c);
        if (c.hasPrior()) {
            priorCnt += 1;
            priorSum += c.getPrior();
        }
    }
    if (!(priorCnt == 0 || (priorCnt == categories.size() && DoubleMath.fuzzyEquals(1., priorSum, 1e-6)))) {
        throw new IllegalArgumentException(
                "Priors should sum up to 1. or not to be given (therefore we initialize the priors to be uniform across classes)");
    }
    if (priorCnt == 0) {
        initializePriors();
    }
    if (priorCnt == categories.size() && DoubleMath.fuzzyEquals(1., priorSum, 1e-6))
        fixedPriors = true;

    //set cost matrix values if not provided
    for (Category from : this.categories.values()) {
        for (Category to : this.categories.values()) {
            if (from.getCost(to.getName()) == null) {
                from.setCost(to.getName(), from.getName().equals(to.getName()) ? 0. : 1.);
            }
        }
    }

    invalidateComputed();
}

From source file:com.analog.lyric.dimple.model.domains.DoubleRangeDomain.java

/**
 * Same as {@link #getIndex(Object)} but taking a double.
 *///from ww w.  j  a v  a 2 s . c o m
@Override
public int getIndex(double value) {
    int index = (int) Math.rint((value - _lowerBound) / _interval);
    return index < _size && DoubleMath.fuzzyEquals(_lowerBound + index * _interval, value, _tolerance) ? index
            : -1;
}

From source file:com.analog.lyric.dimple.solvers.core.parameterizedMessages.DirichletParameters.java

@Override
public double evalEnergy(Value value) {
    final double[] x = value.getDoubleArray();

    final int n = _alphaMinusOne.length;
    if (x.length != n) {
        throw new DimpleException("Argument does not contain %d-dimensional real joint value", n);
    }//  w w  w . j  a v a 2s  .  c o  m

    double sum = 0.0, xSum = 0.0;

    if (isSymmetric()) {
        for (int i = n; --i >= 0;) {
            final double xi = x[i];
            if (xi <= 0) {
                return Double.POSITIVE_INFINITY;
            }

            sum -= Math.log(xi);
            xSum += xi;
        }

        sum *= _alphaMinusOne[0];
    } else {
        for (int i = n; --i >= 0;) {
            final double xi = x[i];
            if (xi <= 0) {
                return Double.POSITIVE_INFINITY;
            }

            sum -= (_alphaMinusOne[i]) * Math.log(xi); // -log(x_i ^ (a_i-1))
            xSum += xi;
        }
    }

    if (!DoubleMath.fuzzyEquals(xSum, 1, SIMPLEX_THRESHOLD * n)) // Values must be on the probability simplex
    {
        return Double.POSITIVE_INFINITY;
    }

    return sum;
}

From source file:com.opengamma.strata.pricer.impl.option.BlackOneTouchCashPriceFormulaRepository.java

/**
 * Computes the price and derivatives of a one-touch/no-touch option.
 * <p>// w  w  w  . j  a v a  2  s.c  om
 * The derivatives are [0] spot, [1] rate, [2] cost-of-carry, [3] volatility, [4] timeToExpiry, [5] spot twice.
 * 
 * @param spot  the spot 
 * @param timeToExpiry  the time to expiry 
 * @param costOfCarry  the cost of carry 
 * @param rate  the interest rate
 * @param lognormalVol  the lognormal volatility
 * @param barrier  the barrier
 * @return the price and derivatives
 */
public ValueDerivatives priceAdjoint(double spot, double timeToExpiry, double costOfCarry, double rate,
        double lognormalVol, SimpleConstantContinuousBarrier barrier) {

    ArgChecker.notNull(barrier, "barrier");
    double[] derivatives = new double[6];
    boolean isKnockIn = barrier.getKnockType().isKnockIn();
    boolean isDown = barrier.getBarrierType().isDown();
    double h = barrier.getBarrierLevel();
    ArgChecker.isFalse(isDown && spot <= barrier.getBarrierLevel(),
            "The Data is not consistent with an alive barrier (DOWN and spot<=barrier).");
    ArgChecker.isFalse(!isDown && spot >= barrier.getBarrierLevel(),
            "The Data is not consistent with an alive barrier (UP and spot>=barrier).");

    double eta = isDown ? 1 : -1;
    double df2 = Math.exp(-rate * timeToExpiry);
    double lognormalVolSq = lognormalVol * lognormalVol;
    double lognormalVolT = lognormalVol * Math.sqrt(timeToExpiry);
    if (DoubleMath.fuzzyEquals(Math.min(timeToExpiry, lognormalVolSq), 0d, SMALL)) {
        if (isKnockIn) {
            return ValueDerivatives.of(0d, DoubleArray.filled(6));
        }
        double price = df2;
        derivatives[1] = -timeToExpiry * price;
        derivatives[4] = -rate * price;
        return ValueDerivatives.of(price, DoubleArray.ofUnsafe(derivatives));
    }
    double mu = (costOfCarry - 0.5 * lognormalVolSq) / lognormalVolSq;
    double lambda = Math.sqrt(mu * mu + 2d * rate / lognormalVolSq);
    double m1 = lognormalVolT * (1d + mu);
    double x2 = Math.log(spot / h) / lognormalVolT + m1;
    double y2 = Math.log(h / spot) / lognormalVolT + m1;
    double z = Math.log(h / spot) / lognormalVolT + lambda * lognormalVolT;
    double[] eDerivFirst = new double[6];
    double[] eDerivSecond = new double[6];
    double[] fDerivFirst = new double[5];
    double[] fDerivSecond = new double[5];
    double price = isKnockIn
            ? getFAdjoint(spot, z, lognormalVolT, h, mu, lambda, eta, fDerivFirst, fDerivSecond)
            : getEAdjoint(spot, df2, x2, y2, lognormalVolT, h, mu, eta, eDerivFirst, eDerivSecond);
    double zBar = 0.0;
    double y2Bar = 0.0;
    double x2Bar = 0.0;
    double zSqBar = 0.0;
    double y2SqBar = 0.0;
    double x2SqBar = 0.0;
    double zsBar = 0.0;
    double y2sBar = 0.0;
    double lambdaBar = 0.0;
    double muBar = 0.0;
    double lognormalVolTBar = 0.0;
    double df2Bar = 0.0;
    if (isKnockIn) {
        zBar = fDerivFirst[1];
        lambdaBar = fDerivFirst[4]; // only F has lambda dependence, which in turn is a function of mu, see muBar+= below
        muBar = fDerivFirst[3];
        lognormalVolTBar = fDerivFirst[2];
        derivatives[0] = fDerivFirst[0];
        zSqBar = fDerivSecond[1];
        zsBar = fDerivSecond[2];
        derivatives[5] = fDerivSecond[0];
    } else {
        y2Bar = eDerivFirst[3];
        x2Bar = eDerivFirst[2];
        muBar = eDerivFirst[5];
        lognormalVolTBar = eDerivFirst[4];
        df2Bar = eDerivFirst[1];
        derivatives[0] = eDerivFirst[0];
        y2SqBar = eDerivSecond[2];
        x2SqBar = eDerivSecond[1];
        y2sBar = eDerivSecond[3];
        derivatives[5] = eDerivSecond[0];
    }
    double dxyds = 1d / spot / lognormalVolT;
    double m1Bar = x2Bar + y2Bar;
    muBar += +lognormalVolT * m1Bar + mu / lambda * lambdaBar;
    lognormalVolTBar += +(lambda - Math.log(h / spot) / (lognormalVolT * lognormalVolT)) * zBar
            - Math.log(h / spot) / (lognormalVolT * lognormalVolT) * y2Bar
            - Math.log(spot / h) / (lognormalVolT * lognormalVolT) * x2Bar + (1 + mu) * m1Bar;
    double lognormalVolSqBar = -costOfCarry / (lognormalVolSq * lognormalVolSq) * muBar
            - rate / (lognormalVolSq * lognormalVolSq) / lambda * lambdaBar;
    derivatives[0] += dxyds * x2Bar - dxyds * y2Bar - dxyds * zBar;
    derivatives[1] = -timeToExpiry * df2 * df2Bar + lambdaBar / lambda / lognormalVolSq;
    derivatives[2] = muBar / lognormalVolSq;
    derivatives[3] = 2d * lognormalVol * lognormalVolSqBar + Math.sqrt(timeToExpiry) * lognormalVolTBar;
    derivatives[4] = -rate * df2 * df2Bar + lognormalVolTBar * lognormalVolT * 0.5 / timeToExpiry;
    derivatives[5] += -dxyds * x2Bar / spot + dxyds * y2Bar / spot + dxyds * zBar / spot
            + dxyds * dxyds * x2SqBar + dxyds * dxyds * y2SqBar - 2d * dxyds * y2sBar + dxyds * dxyds * zSqBar
            - 2d * dxyds * zsBar;
    return ValueDerivatives.of(price, DoubleArray.ofUnsafe(derivatives));
}

From source file:com.opengamma.strata.pricer.impl.option.BlackOneTouchAssetPriceFormulaRepository.java

/**
 * Computes the price and derivatives of a one-touch/no-touch option.
 * <p>/*from  ww w .j av  a 2s  .c o  m*/
 * The derivatives are [0] spot, [1] rate, [2] cost-of-carry, [3] volatility, [4] timeToExpiry, [5] spot twice.
 * 
 * @param spot  the spot 
 * @param timeToExpiry  the time to expiry 
 * @param costOfCarry  the cost of carry 
 * @param rate  the interest rate
 * @param lognormalVol  the lognormal volatility
 * @param barrier  the barrier
 * @return the price and derivatives
 */
public ValueDerivatives priceAdjoint(double spot, double timeToExpiry, double costOfCarry, double rate,
        double lognormalVol, SimpleConstantContinuousBarrier barrier) {

    ArgChecker.notNull(barrier, "barrier");
    double[] derivatives = new double[6];
    boolean isKnockIn = barrier.getKnockType().isKnockIn();
    boolean isDown = barrier.getBarrierType().isDown();
    double h = barrier.getBarrierLevel();
    ArgChecker.isFalse(isDown && spot <= barrier.getBarrierLevel(),
            "The Data is not consistent with an alive barrier (DOWN and spot<=barrier).");
    ArgChecker.isFalse(!isDown && spot >= barrier.getBarrierLevel(),
            "The Data is not consistent with an alive barrier (UP and spot>=barrier).");

    double eta = isDown ? 1 : -1;
    double df1 = Math.exp(timeToExpiry * (costOfCarry - rate));
    double lognormalVolSq = lognormalVol * lognormalVol;
    double lognormalVolT = lognormalVol * Math.sqrt(timeToExpiry);
    if (DoubleMath.fuzzyEquals(Math.min(timeToExpiry, lognormalVolSq), 0d, SMALL)) {
        if (isKnockIn) {
            return ValueDerivatives.of(0d, DoubleArray.filled(6));
        }
        double price = df1 * spot;
        derivatives[0] = df1;
        derivatives[1] = -timeToExpiry * price;
        derivatives[2] = timeToExpiry * price;
        derivatives[4] = (costOfCarry - rate) * price;
        return ValueDerivatives.of(price, DoubleArray.ofUnsafe(derivatives));
    }
    double mu = (costOfCarry - 0.5 * lognormalVolSq) / lognormalVolSq;
    double lambda = Math.sqrt(mu * mu + 2d * rate / lognormalVolSq);
    double m1 = lognormalVolT * (1d + mu);
    double x2 = Math.log(spot / h) / lognormalVolT + m1;
    double y2 = Math.log(h / spot) / lognormalVolT + m1;
    double z = Math.log(h / spot) / lognormalVolT + lambda * lognormalVolT;
    double[] eDerivFirst = new double[6];
    double[] eDerivSecond = new double[5];
    double[] fDerivFirst = new double[5];
    double[] fDerivSecond = new double[5];
    double price = isKnockIn
            ? getFAdjoint(spot, z, lognormalVolT, h, mu, lambda, eta, h, fDerivFirst, fDerivSecond)
            : getEAdjoint(spot, df1, x2, y2, h, mu, eta, eDerivFirst, eDerivSecond);
    double zBar = 0.0;
    double y2Bar = 0.0;
    double x2Bar = 0.0;
    double zSqBar = 0.0;
    double y2SqBar = 0.0;
    double x2SqBar = 0.0;
    double zsBar = 0.0;
    double x2sBar = 0.0;
    double y2sBar = 0.0;
    double lambdaBar = 0.0;
    double muBar = 0.0;
    double lognormalVolTBar = 0.0;
    double df1Bar = 0.0;
    if (isKnockIn) {
        zBar = fDerivFirst[1];
        lambdaBar = fDerivFirst[4];
        muBar = fDerivFirst[3];
        lognormalVolTBar = fDerivFirst[2];
        derivatives[0] = fDerivFirst[0];
        zSqBar = fDerivSecond[1];
        zsBar = fDerivSecond[2];
        derivatives[5] = fDerivSecond[0];
    } else {
        y2Bar = eDerivFirst[3];
        x2Bar = eDerivFirst[2];
        muBar = eDerivFirst[4];
        df1Bar = eDerivFirst[1];
        derivatives[0] = eDerivFirst[0];
        x2SqBar = eDerivSecond[1];
        y2SqBar = eDerivSecond[2];
        x2sBar = eDerivSecond[3];
        y2sBar = eDerivSecond[4];
        derivatives[5] = eDerivSecond[0];
    }
    double dxyds = 1d / spot / lognormalVolT;
    double m1Bar = x2Bar + y2Bar;
    muBar += lognormalVolT * m1Bar + mu / lambda * lambdaBar;
    lognormalVolTBar += +(lambda - Math.log(h / spot) / (lognormalVolT * lognormalVolT)) * zBar
            - Math.log(h / spot) / (lognormalVolT * lognormalVolT) * y2Bar
            - Math.log(spot / h) / (lognormalVolT * lognormalVolT) * x2Bar + (1 + mu) * m1Bar;
    double lognormalVolSqBar = -costOfCarry / (lognormalVolSq * lognormalVolSq) * muBar
            - rate / (lognormalVolSq * lognormalVolSq) / lambda * lambdaBar;
    derivatives[0] += dxyds * x2Bar - dxyds * y2Bar - dxyds * zBar;
    derivatives[1] = 1d / lambda / lognormalVolSq * lambdaBar - timeToExpiry * df1 * df1Bar;
    derivatives[2] = 1d / lognormalVolSq * muBar + timeToExpiry * df1 * df1Bar;
    derivatives[3] = 2d * lognormalVol * lognormalVolSqBar + Math.sqrt(timeToExpiry) * lognormalVolTBar;
    derivatives[4] = +(costOfCarry - rate) * df1 * df1Bar
            + lognormalVolTBar * lognormalVolT * 0.5 / timeToExpiry;
    derivatives[5] += -dxyds * x2Bar / spot + dxyds * y2Bar / spot + dxyds * zBar / spot
            + dxyds * dxyds * x2SqBar + 2d * dxyds * x2sBar + dxyds * dxyds * y2SqBar - 2d * dxyds * y2sBar
            + dxyds * dxyds * zSqBar - 2d * dxyds * zsBar;
    return ValueDerivatives.of(price, DoubleArray.ofUnsafe(derivatives));
}