List of usage examples for com.google.common.math DoubleMath fuzzyEquals
public static boolean fuzzyEquals(double a, double b, double tolerance)
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)); }