Example usage for java.lang Math exp

List of usage examples for java.lang Math exp

Introduction

In this page you can find the example usage for java.lang Math exp.

Prototype

@HotSpotIntrinsicCandidate
public static double exp(double a) 

Source Link

Document

Returns Euler's number e raised to the power of a double value.

Usage

From source file:com.wwidesigner.util.PhysicalParameters.java

/**
 * Compute the actual air pressure, in kPa, at specified elevation,
  * from the barometric formula./*w  ww.  j ava2s .  co m*/
  * @param barometricPressure - pressure shown on barometer, adjusted to sea-level
 * @param elevation - elevation in meters
 * @return absolute air pressure, in kPa
 */
static public double pressureAt(double barometricPressure, double elevation) {
    // Concentration of CO2 in the atmosphere.
    double xCO2 = 0.000390;
    // Standard molar mass of air, in kg/kmol.
    double Ma = Ma0 + (Mco2 - Mo2) * xCO2;
    // Gravitational acceleration, in m/s^2
    double g = 9.80665;
    return barometricPressure * Math.exp(-g * Ma * 0.001 * elevation / (R * 288.15));
}

From source file:com.opengamma.analytics.financial.model.option.pricing.tree.LogNormalBinomialTreeBuilderTest.java

@Test
public void testCEV() {
    final GeneralLogNormalOptionDataBundle data = new GeneralLogNormalOptionDataBundle(YIELD_CURVE, DRIFTLESS,
            new VolatilitySurface(FunctionalDoublesSurface.from(CEV_LOCAL_VOL)), FORWARD, DATE);
    final RecombiningBinomialTree<BinomialTreeNode<Double>> assetPriceTree = BUILDER.buildAssetTree(T, data,
            200);/* ww w  .  ja  va 2s . c o  m*/
    RecombiningBinomialTree<BinomialTreeNode<Double>> optionPriceTree = BUILDER.buildOptionPriceTree(OPTION,
            data, assetPriceTree);
    EuropeanVanillaOption o = new EuropeanVanillaOption(FORWARD, T, true);
    final CEVFunctionData cfd = new CEVFunctionData(FORWARD, YIELD_CURVE.getDiscountFactor(T), SIGMA_BETA,
            BETA);

    for (int i = 0; i < 10; i++) {
        final double m = -1.5 + 3.0 * i / 10.0;
        final double strike = FORWARD * Math.exp(ATM_VOL * Math.sqrt(T) * m);
        final OptionDefinition option = new EuropeanVanillaOptionDefinition(strike, OPTION.getExpiry(),
                OPTION.isCall());
        optionPriceTree = BUILDER.buildOptionPriceTree(option, data, assetPriceTree);
        o = new EuropeanVanillaOption(strike, T, true);
        final double cevPrice = CEV_PRICE.getPriceFunction(o).evaluate(cfd);
        final double cevVol = BLACK_IMPLIED_VOL.getImpliedVolatility(
                new BlackFunctionData(FORWARD, YIELD_CURVE.getDiscountFactor(T), SIGMA_BETA), o, cevPrice);
        final double impVol = BLACK_IMPLIED_VOL.getImpliedVolatility(
                new BlackFunctionData(FORWARD, YIELD_CURVE.getDiscountFactor(T), SIGMA_BETA), o,
                optionPriceTree.getNode(0, 0).getValue());
        //      final double cevPrice = CEVFormula.optionPrice(FORWARD, strike, BETA, df, SIGMA_BETA, T, true);
        //      final double cevVol = BlackImpliedVolFormula.impliedVol(cevPrice, FORWARD, strike, df, T, true);
        //      final double impVol = BlackImpliedVolFormula.impliedVol(optionPriceTree.getNode(0, 0).getValue(), FORWARD, strike, df, T, true);
        // System.out.println(strike + "\t" + cevVol  + "\t" + impVol);
        assertEquals(cevVol, impVol, 1e-3);
    }
}

From source file:com.opengamma.analytics.financial.interestrate.inflation.method.InflationMarketModelConvexityAdjustmentForCapFloor.java

/**
 * Computes the convexity adjustment for zero coupon inflation swap with an interpolated index.
* @param coupon The zero-coupon payment.
 * @param inflationConvexity The inflation provider.
 * @return The convexity adjustment.//from  w  w w. j  a va  2 s  .  c  o m
 */
public double getZeroCouponConvexityAdjustment(final CapFloorInflationZeroCouponInterpolation coupon,
        final BlackSmileCapInflationZeroCouponWithConvexityProviderInterface inflationConvexity) {
    Validate.notNull(coupon, "Coupon");
    Validate.notNull(inflationConvexity, "Inflation");

    final double fixingTime = coupon.getWeight() * coupon.getReferenceEndTime()[0]
            + (1 - coupon.getWeight()) * coupon.getReferenceEndTime()[1];
    final double naturalPaymentTime = coupon.getNaturalPaymentTime();
    final double paymentTime = coupon.getPaymentTime();

    final double volatility = inflationConvexity.getInflationConvexityAdjustmentParameters()
            .getPriceIndexAtmVolatility()[0];
    final double correlationInflationRate = inflationConvexity.getInflationConvexityAdjustmentParameters()
            .getPriceIndexRateCorrelation().getYValue(fixingTime);
    final double volBondForward = getVolBondForward(naturalPaymentTime, paymentTime, inflationConvexity);
    final double adjustment = volatility * volBondForward * correlationInflationRate * naturalPaymentTime;
    return Math.exp(adjustment);
}

From source file:com.opengamma.analytics.financial.interestrate.inflation.method.InflationMarketModelConvexityAdjustmentForCoupon.java

/**
 * Computes the convexity adjustment for year on year inflation coupon with margin with a monthly index.
 * @param coupon The year on year coupon.
 * @param inflationConvexity The inflation provider.
 * @return The convexity adjustment./*from  www .  jav a2 s  .c  o  m*/
 */
public double getYearOnYearConvexityAdjustment(final CouponInflationYearOnYearMonthlyWithMargin coupon,
        final InflationConvexityAdjustmentProviderInterface inflationConvexity) {
    Validate.notNull(coupon, "Coupon");
    Validate.notNull(inflationConvexity, "Inflation");

    final double firstFixingTime = coupon.getReferenceStartTime();
    final double secondFixingTime = coupon.getReferenceEndTime();
    final double firstNaturalPaymentTime = coupon.getNaturalPaymentStartTime();
    final double secondNaturalPaymentTime = coupon.getNaturalPaymentEndTime();
    final double paymentTime = coupon.getPaymentTime();
    final double volatilityStart = inflationConvexity.getInflationConvexityAdjustmentParameters()
            .getPriceIndexAtmVolatility()[0];
    final double volatilityEnd = inflationConvexity.getInflationConvexityAdjustmentParameters()
            .getPriceIndexAtmVolatility()[1];
    final double correlationInflation = inflationConvexity.getInflationConvexityAdjustmentParameters()
            .getPriceIndexCorrelation().getZValue(firstFixingTime, secondFixingTime);
    final double correlationInflationRateStart = inflationConvexity.getInflationConvexityAdjustmentParameters()
            .getPriceIndexRateCorrelation().getYValue(firstFixingTime);
    final double correlationInflationRateEnd = inflationConvexity.getInflationConvexityAdjustmentParameters()
            .getPriceIndexRateCorrelation().getYValue(secondFixingTime);
    final double volBondForwardStart = getVolBondForward(firstNaturalPaymentTime, paymentTime,
            inflationConvexity);
    final double volBondForwardEnd = getVolBondForward(secondNaturalPaymentTime, paymentTime,
            inflationConvexity);
    final double adjustment = volatilityStart
            * (volatilityStart - volatilityEnd * correlationInflation
                    - volBondForwardStart * correlationInflationRateStart)
            * firstNaturalPaymentTime
            + volatilityEnd * volBondForwardEnd * correlationInflationRateEnd * secondNaturalPaymentTime;
    return Math.exp(adjustment);

}

From source file:etomica.virial.MCMoveClusterRingRegrowOrientation.java

public boolean doTrial() {

    weightOld = ((BoxCluster) box).getSampleCluster().value((BoxCluster) box);
    IVectorRandom e1 = (IVectorRandom) space.makeVector();
    IVectorMutable ex = space.makeVector();
    IVectorMutable ey = space.makeVector();
    IVectorMutable ez = space.makeVector();
    ex.setX(0, 1);/*from   ww  w.j a  v  a  2s  .co  m*/
    ey.setX(1, 1);
    ez.setX(2, 1);
    IVectorMutable oldCenter = space.makeVector();
    IVectorMutable newCenter = space.makeVector();
    IMoleculeList molecules = box.getMoleculeList();
    IOrientation3D[][] newOrientations = new IOrientation3D[molecules.getMoleculeCount()][P + 1];
    double[] oldAlpha = new double[P];
    newAlpha = new double[P];
    double[] theta = new double[P];
    int fromImage = 0;
    int toImage = 0;
    double uOld = 0;
    double uNew = 0;
    double pGenRatio = 1.00;
    IVectorMutable pVecOld = space.makeVector();
    IVectorMutable pVecNew = space.makeVector();

    int nMolecules = molecules.getMoleculeCount();
    for (int i = 0; i < nMolecules; i++) {
        IMolecule molecule = molecules.getMolecule(i);
        IAtomList atoms = molecule.getChildList();
        for (int j = 0; j < P; j++) {
            int prev = j - 1;
            if (prev < 0)
                prev = P - 1;
            AtomHydrogen jAtom = (AtomHydrogen) atoms.getAtom(j);
            AtomHydrogen jPrev = (AtomHydrogen) atoms.getAtom(prev);
            double distance = dist(jAtom, jPrev);
            uOld += kHarmonic * distance;
        }
        oldOrientations[i][0].setDirection(((IAtomOriented) atoms.getAtom(0)).getOrientation().getDirection());
        IVectorRandom rV1 = (IVectorRandom) space.makeVector();
        rV1.setRandomSphere(random);
        newOrientations[i][0] = (IOrientation3D) ((IAtomOriented) atoms.getAtom(0)).getOrientation();
        newOrientations[i][0].setDirection(rV1);
        oldOrientations[i][P].setDirection(oldOrientations[i][0].getDirection());
        newOrientations[i][P] = (IOrientation3D) space.makeOrientation();
        newOrientations[i][P].setDirection(newOrientations[i][0].getDirection());
        pVecOld.E(oldOrientations[i][0].getDirection());
        pVecNew.E(newOrientations[i][0].getDirection());
        for (int dr = 2; dr <= P; dr *= 2) {
            double kEff = 8 * kHarmonic * dr / P;
            double y0 = 0;
            double sA = 0;
            double kEff1Old = 0;
            double kEff1New = 0;
            double a = 0;
            double y1 = 0;
            for (int nr = 1; nr < dr; nr += 2) {
                int imageIndex = nr * P / dr;
                //                    System.out.println("image # = "+imageIndex);                    
                IAtomOriented jAtom = ((IAtomOriented) atoms.getAtom(imageIndex));
                oldOrientations[i][imageIndex].setDirection(jAtom.getOrientation().getDirection());
                newOrientations[i][imageIndex] = (IOrientation3D) jAtom.getOrientation();
                fromImage = (nr - 1) * P / dr;
                toImage = (nr + 1) * P / dr;
                double r = 0;
                for (int k = fromImage; k <= toImage; k++) {
                    if (k == P) {
                        r += ((AtomHydrogen) atoms.getAtom(0)).getBondLength() / 2.0;
                    } else {
                        r += ((AtomHydrogen) atoms.getAtom(k)).getBondLength() / 2.0;
                    }

                }
                r *= dr / (2.0 * P + dr); // same as r /= (toImage - fromImage + 1)

                if (imageIndex == P / 2 && doExchange) {
                    pVecOld.TE(-1);
                    pVecNew.TE(-1);
                    oldOrientations[i][P].setDirection(pVecOld);
                    newOrientations[i][P].setDirection(pVecNew);
                } else {
                    oldCenter.Ev1Pv2(oldOrientations[i][fromImage].getDirection(),
                            oldOrientations[i][toImage].getDirection());
                    oldCenter.normalize();
                    y0 = oldOrientations[i][fromImage].getDirection()
                            .dot(oldOrientations[i][toImage].getDirection());
                    if (y0 > 1.0)
                        y0 = 1.0;
                    if (y0 < -1.0)
                        y0 = -1.0;
                    kEff1Old = kEff * r * r * Math.sqrt((1 + y0) / 2.0);
                    y0 = newOrientations[i][fromImage].getDirection()
                            .dot(newOrientations[i][toImage].getDirection());
                    if (y0 > 1.0)
                        y0 = 1.0;
                    if (y0 < -1.0)
                        y0 = -1.0;
                    kEff1New = kEff * r * r * Math.sqrt((1 + y0) / 2.0);
                    y0 = oldCenter.dot(oldOrientations[i][imageIndex].getDirection());
                    if (y0 > 1.0)
                        y0 = 1.0;
                    if (y0 < -1.0)
                        y0 = -1.0;
                    oldAlpha[imageIndex] = Math.acos(y0);
                    double x = random.nextDouble();
                    //                     double y1_new = (-kEff1New + Math.log(Math.exp(2*kEff1New)-x*(Math.exp(2*kEff1New)-1)))/kEff1New;                                        
                    a = Math.log(1 - x) / kEff1New
                            + Math.log(1 + x * Math.exp(-2 * kEff1New) / (1 - x)) / kEff1New;
                    //                     double a = Math.log(1 - xNew[i][imageIndex])/kEff1New + Math.log(1 + xNew[i][imageIndex]*Math.exp(-2*kEff1New)/(1-xNew[i][imageIndex]))/kEff1New;

                    if (a > 0) {
                        a = 0;
                    }
                    if (a < -2.0) {
                        a = -2.0;
                    }
                    y1 = 1 + a;
                    sA = Math.sqrt(-2 * a - a * a);
                    if (Double.isNaN(sA))
                        throw new RuntimeException(a + " " + (2 * a + a * a));
                    newAlpha[imageIndex] = Math.acos(y1);
                    if (newAlpha[imageIndex] != newAlpha[imageIndex] || y1 != y1)
                        throw new RuntimeException("x = " + 2 * kEff1New);

                }
                if (imageIndex == P / 2) {
                    newOrientations[i][imageIndex].setDirection(rV1);
                    IVectorMutable rV2 = space.makeVector();
                    if (Math.abs(rV1.getX(0)) > 0.5) {
                        rV2.setX(1, 1);
                    } else {
                        rV2.setX(0, 1);
                    }
                    rV2.PEa1Tv1(-rV2.dot(rV1), rV1);
                    rV2.normalize();
                    double dummyAlpha = 2 * Math.PI * random.nextDouble();
                    rotateVectorV(dummyAlpha, rV1, rV2);

                    if (!doExchange) {
                        rotateVectorV(newAlpha[imageIndex], rV2,
                                (IVectorMutable) newOrientations[i][imageIndex].getDirection());
                    } else {
                        double angle = 2 * Math.PI * random.nextDouble();
                        rotateVectorV(angle, rV2,
                                (IVectorMutable) newOrientations[i][imageIndex].getDirection());
                    }
                    theta[imageIndex] = 0;

                } else {
                    newCenter.Ev1Pv2(newOrientations[i][fromImage].getDirection(),
                            newOrientations[i][toImage].getDirection());
                    newCenter.normalize();
                    newOrientations[i][imageIndex].setDirection(newCenter);

                    e1.E(0);
                    if (Math.abs(newCenter.getX(0)) > 0.5) {
                        e1.setX(1, 1);
                    } else {
                        e1.setX(0, 1);
                    }
                    e1.PEa1Tv1(-e1.dot(newCenter), newCenter);
                    e1.normalize();

                    rotateVectorV(newAlpha[imageIndex], e1,
                            (IVectorMutable) newOrientations[i][imageIndex].getDirection());
                    theta[imageIndex] = random.nextDouble() * 2 * Math.PI;
                    newOrientations[i][imageIndex].rotateBy(theta[imageIndex], newCenter);
                }
                if (newOrientations[i][imageIndex].getDirection().isNaN())
                    throw new RuntimeException("bead " + imageIndex + " orientation is NaN");
                if (!doExchange || imageIndex != P / 2) {
                    oldCenter.ME(oldOrientations[i][imageIndex].getDirection());
                    double v = oldCenter.squared();
                    double v1 = oldCenter.dot(oldOrientations[i][imageIndex].getDirection());
                    double s1 = v - v1 * v1;
                    double y0m1 = -s1 / (1 + y0);
                    //                     if (xOld[i][imageIndex] == 0) xOld[i][imageIndex] = xNew[i][imageIndex];
                    //                     pGenOld *= Math.exp(kEff1Old*y0)*kEff1Old/Math.sinh(kEff1Old);                    
                    //                     pGenNew *= Math.exp(kEff1New*y1)*kEff1New/Math.sinh(kEff1New);
                    //                     pGenOld *= 2*Math.exp(kEff1Old*y0m1)*kEff1Old/(1 - Math.exp(-2*kEff1Old));                    
                    //                     pGenNew *= 2*Math.exp(kEff1New*a)*kEff1New/(1 - Math.exp(-2*kEff1New));
                    //                     System.out.println(kEff1Old+" "+kEff1New+" "+y0m1+" "+(y0-1)+" "+a+" "+(y1_new-1));
                    //                     pGenRatio *= Math.exp(kEff1New*a - kEff1Old*y0m1)*kEff1New*(1-Math.exp(-2*kEff1Old))/(kEff1Old*(1-Math.exp(-2*kEff1New)));
                    //                     double aNew = kEff1New*(-xNew[i][imageIndex] + 1/(1 - Math.exp(-2*kEff1New)))/(kEff1Old*(-xOld[i][imageIndex] + 1/(1 - Math.exp(-2*kEff1Old))));
                    double aOld = Math.exp(kEff1New * a - kEff1Old * y0m1) * kEff1New
                            * (1 - Math.exp(-2 * kEff1Old)) / (kEff1Old * (1 - Math.exp(-2 * kEff1New)));

                    pGenRatio *= aOld;
                    if (Double.isNaN(pGenRatio))
                        throw new RuntimeException();
                }
            }
        }
        for (int j = 0; j < P; j++) {
            int prev = j - 1;
            if (prev < 0)
                prev = P - 1;
            AtomHydrogen jAtom = (AtomHydrogen) atoms.getAtom(j);
            AtomHydrogen jPrev = (AtomHydrogen) atoms.getAtom(prev);
            uNew += kHarmonic * dist(jAtom, jPrev);
        }
    }
    double pActRatio = Math.exp(uOld - uNew);
    uAcc = uNew;
    pacc = pActRatio / pGenRatio;

    ((BoxCluster) box).trialNotify();
    weightNew = ((BoxCluster) box).getSampleCluster().value((BoxCluster) box);

    return true;
}

From source file:com.opengamma.financial.analytics.ircurve.InterpolatedYieldAndDiscountCurveFunction.java

@Override
public CompiledFunctionDefinition compile(final FunctionCompilationContext context, final Instant atInstant) {
    final Triple<Instant, Instant, InterpolatedYieldCurveSpecification> compile = _helper.compile(context,
            atInstant, this);

    final InterpolatedYieldCurveSpecification specification = compile.getThird();

    // ENG-252 see MarkingInstrumentImpliedYieldCurveFunction; need to work out the expiry more efficiently
    return new AbstractInvokingCompiledFunction(compile.getFirst(), compile.getSecond()) {

        @Override/*  w w  w .  ja v  a2s .c  o  m*/
        public ComputationTargetType getTargetType() {
            return ComputationTargetType.CURRENCY;
        }

        @Override
        public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) {
            return _definition.getCurrency().equals(target.getValue());
        }

        @Override
        public Set<ValueSpecification> getResults(final FunctionCompilationContext context,
                final ComputationTarget target) {
            return _results;
        }

        @Override
        public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context,
                final ComputationTarget target, final ValueRequirement desiredValue) {
            final Set<ValueRequirement> result = new HashSet<ValueRequirement>();
            result.add(_helper.getMarketDataValueRequirement());
            return result;
        }

        @Override
        public Set<ComputedValue> execute(final FunctionExecutionContext executionContext,
                final FunctionInputs inputs, final ComputationTarget target,
                final Set<ValueRequirement> desiredValues) {
            final SnapshotDataBundle marketData = _helper.getMarketDataMap(inputs);
            // Gather market data rates
            // Note that this assumes that all strips are priced in decimal percent. We need to resolve
            // that ultimately in OG-LiveData normalization and pull out the OGRate key rather than
            // the crazy IndicativeValue name.
            final FixedIncomeStripIdentifierAndMaturityBuilder builder = new FixedIncomeStripIdentifierAndMaturityBuilder(
                    OpenGammaExecutionContext.getRegionSource(executionContext),
                    OpenGammaExecutionContext.getConventionBundleSource(executionContext),
                    executionContext.getSecuritySource(),
                    OpenGammaExecutionContext.getHolidaySource(executionContext));
            final InterpolatedYieldCurveSpecificationWithSecurities specWithSecurities = builder
                    .resolveToSecurity(specification, marketData);
            final Clock snapshotClock = executionContext.getValuationClock();
            final ZonedDateTime today = ZonedDateTime.now(snapshotClock); // TODO: change to times
            final Map<Double, Double> timeInYearsToRates = new TreeMap<Double, Double>();
            boolean isFirst = true;
            for (final FixedIncomeStripWithSecurity strip : specWithSecurities.getStrips()) {
                Double price = marketData.getDataPoint(strip.getSecurityIdentifier());
                if (strip.getInstrumentType() == StripInstrumentType.FUTURE) {
                    price = 100d - price;
                }
                price /= 100d;
                if (_isYieldCurve) {
                    final double years = DateUtils.getDifferenceInYears(today, strip.getMaturity());
                    timeInYearsToRates.put(years, price);
                } else {
                    if (isFirst) {
                        timeInYearsToRates.put(0., 1.);
                        isFirst = false;
                    }
                    final double years = DateUtils.getDifferenceInYears(today, strip.getMaturity());
                    timeInYearsToRates.put(years, Math.exp(-price * years));
                }
            }
            final YieldAndDiscountCurve curve = _isYieldCurve
                    ? YieldCurve.from(InterpolatedDoublesCurve.from(timeInYearsToRates, _interpolator))
                    : DiscountCurve.from(InterpolatedDoublesCurve.from(timeInYearsToRates, _interpolator));
            final ComputedValue resultValue = new ComputedValue(_result, curve);
            final ComputedValue specValue = new ComputedValue(_specResult, specWithSecurities);
            return Sets.newHashSet(resultValue, specValue);
        }

    };
}

From source file:com.idylwood.utils.MathUtils.java

public static final double[] exp(final double[] data) {
    final double[] ret = new double[data.length];
    for (int i = 0; i < data.length; i++)
        ret[i] = Math.exp(data[i]);
    return ret;//from  w  w w .  j  ava2s.  com
}

From source file:br.prof.salesfilho.oci.image.ImageProcessor.java

/**
 * @param channel RGB and grayscale (1 = RED, 2 = GREEN, 3 = BLUE and 4 =
 * GRAYSCALE, diferent value GRAYSCALE is returned)
 * @param kernel Kernel size//  w w w .  j av  a 2  s  . c o  m
 * @return AutoCorrentropy array
 */
private double[] getAutoCorrentropy(int channel, double kernel) {

    double[] signal = this.getZigZagVetorized(this.getColorMatrix(channel));

    double twokSizeSquare = 2 * Math.pow(kernel, 2d);
    int signal_length = signal.length;
    double[] autoCorrentropy = new double[signal_length];
    double b = 1 / kernel * Math.sqrt(2 * Math.PI);
    int N = signal_length;

    for (int m = 0; m < signal_length; m++) {
        for (int n = m + 1; n < signal_length; n++) {
            double pow = Math.pow((signal[n] - signal[n - m - 1]), 2);
            double exp = Math.exp(-pow / twokSizeSquare);
            double equation = (1d / (N - m + 1d)) * b * exp;
            autoCorrentropy[m] = autoCorrentropy[m] + equation;
        }
    }
    return autoCorrentropy;
}

From source file:es.emergya.geo.util.Lambert.java

/**
 * Initializes from projected coordinates (conic projection). Note that
 * reference ellipsoid used by Lambert is Clark
 *
 * @param eastNorth projected coordinates pair in meters
 * @param Xs        false east (coordinate system origin) in meters
 * @param Ys        false north (coordinate system origin) in meters
 * @param c         projection constant// ww w .j  a  va2s.  co  m
 * @param n         projection exponent
 * @return LatLon in radian
 */
private LatLon Geographic(EastNorth eastNorth, double Xs, double Ys, double c, double n) {
    double dx = eastNorth.east() - Xs;
    double dy = Ys - eastNorth.north();
    double R = Math.sqrt(dx * dx + dy * dy);
    double gamma = Math.atan(dx / dy);
    double l = -1.0 / n * Math.log(Math.abs(R / c));
    l = Math.exp(l);
    double lon = lg0 + gamma / n;
    double lat = 2.0 * Math.atan(l) - Math.PI / 2.0;
    double delta = 1.0;
    while (delta > epsilon) {
        double eslt = Ellipsoid.clarke.e * Math.sin(lat);
        double nlt = 2.0 * Math.atan(Math.pow((1.0 + eslt) / (1.0 - eslt), Ellipsoid.clarke.e / 2.0) * l)
                - Math.PI / 2.0;
        delta = Math.abs(nlt - lat);
        lat = nlt;
    }
    return new LatLon(lat, lon); // in radian
}