110 lines
3.2 KiB
Java
110 lines
3.2 KiB
Java
package org.stellar.sdk;
|
|
|
|
import com.google.gson.annotations.SerializedName;
|
|
import org.stellar.sdk.xdr.Int32;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import static com.google.common.base.Preconditions.checkNotNull;
|
|
|
|
/**
|
|
* Represents Price. Price in Stellar is represented as a fraction.
|
|
*/
|
|
public class Price {
|
|
@SerializedName("n")
|
|
private final int n;
|
|
@SerializedName("d")
|
|
private final int d;
|
|
|
|
/**
|
|
* Create a new price. Price in Stellar is represented as a fraction.
|
|
* @param n numerator
|
|
* @param d denominator
|
|
*/
|
|
public Price(int n, int d) {
|
|
this.n = n;
|
|
this.d = d;
|
|
}
|
|
|
|
/**
|
|
* Returns numerator.
|
|
*/
|
|
public int getNumerator() {
|
|
return n;
|
|
}
|
|
|
|
/**
|
|
* Returns denominator
|
|
*/
|
|
public int getDenominator() {
|
|
return d;
|
|
}
|
|
|
|
/**
|
|
* Approximates <code>price</code> to a fraction.
|
|
* Please remember that this function can give unexpected results for values that cannot be represented as a
|
|
* fraction with 32-bit numerator and denominator. It's safer to create a Price object using the constructor.
|
|
* @param price Ex. "1.25"
|
|
*/
|
|
public static Price fromString(String price) {
|
|
checkNotNull(price, "price cannot be null");
|
|
BigDecimal maxInt = new BigDecimal(Integer.MAX_VALUE);
|
|
BigDecimal number = new BigDecimal(price);
|
|
BigDecimal a;
|
|
BigDecimal f;
|
|
List<BigDecimal[]> fractions = new ArrayList<BigDecimal[]>();
|
|
fractions.add(new BigDecimal[]{new BigDecimal(0), new BigDecimal(1)});
|
|
fractions.add(new BigDecimal[]{new BigDecimal(1), new BigDecimal(0)});
|
|
int i = 2;
|
|
while (true) {
|
|
if (number.compareTo(maxInt) > 0) {
|
|
break;
|
|
}
|
|
a = number.setScale(0, BigDecimal.ROUND_FLOOR);
|
|
f = number.subtract(a);
|
|
BigDecimal h = a.multiply(fractions.get(i - 1)[0]).add(fractions.get(i - 2)[0]);
|
|
BigDecimal k = a.multiply(fractions.get(i - 1)[1]).add(fractions.get(i - 2)[1]);
|
|
if (h.compareTo(maxInt) > 0 || k.compareTo(maxInt) > 0) {
|
|
break;
|
|
}
|
|
fractions.add(new BigDecimal[]{h, k});
|
|
if (f.compareTo(BigDecimal.ZERO) == 0) {
|
|
break;
|
|
}
|
|
number = new BigDecimal(1).divide(f, 20, BigDecimal.ROUND_HALF_UP);
|
|
i = i + 1;
|
|
}
|
|
BigDecimal n = fractions.get(fractions.size()-1)[0];
|
|
BigDecimal d = fractions.get(fractions.size()-1)[1];
|
|
return new Price(n.intValue(), d.intValue());
|
|
}
|
|
|
|
/**
|
|
* Generates Price XDR object.
|
|
*/
|
|
public org.stellar.sdk.xdr.Price toXdr() {
|
|
org.stellar.sdk.xdr.Price xdr = new org.stellar.sdk.xdr.Price();
|
|
Int32 n = new Int32();
|
|
Int32 d = new Int32();
|
|
n.setInt32(this.n);
|
|
d.setInt32(this.d);
|
|
xdr.setN(n);
|
|
xdr.setD(d);
|
|
return xdr;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object object) {
|
|
if (!(object instanceof Price)) {
|
|
return false;
|
|
}
|
|
|
|
Price price = (Price) object;
|
|
|
|
return this.getNumerator() == price.getNumerator() &&
|
|
this.getDenominator() == price.getDenominator();
|
|
|
|
}
|
|
}
|