Example #1
0
// continuedFraction calculates and returns the best rational approximation of the given real number.
func continuedFraction(price string) (xdrPrice xdr.Price, err error) {
	number := &big.Rat{}
	maxInt32 := &big.Rat{}
	zero := &big.Rat{}
	one := &big.Rat{}

	_, ok := number.SetString(price)
	if !ok {
		return xdrPrice, fmt.Errorf("cannot parse price: %s", price)
	}

	maxInt32.SetInt64(int64(math.MaxInt32))
	zero.SetInt64(int64(0))
	one.SetInt64(int64(1))

	fractions := [][2]*big.Rat{
		{zero, one},
		{one, zero},
	}

	i := 2
	for {
		if number.Cmp(maxInt32) == 1 {
			break
		}

		f := &big.Rat{}
		h := &big.Rat{}
		k := &big.Rat{}

		a := floor(number)
		f.Sub(number, a)
		h.Mul(a, fractions[i-1][0])
		h.Add(h, fractions[i-2][0])
		k.Mul(a, fractions[i-1][1])
		k.Add(k, fractions[i-2][1])

		if h.Cmp(maxInt32) == 1 || k.Cmp(maxInt32) == 1 {
			break
		}

		fractions = append(fractions, [2]*big.Rat{h, k})
		if f.Cmp(zero) == 0 {
			break
		}
		number.Quo(one, f)
		i++
	}

	n, d := fractions[len(fractions)-1][0], fractions[len(fractions)-1][1]

	if n.Cmp(zero) == 0 || d.Cmp(zero) == 0 {
		return xdrPrice, errors.New("Couldn't find approximation")
	}

	return xdr.Price{
		N: xdr.Int32(n.Num().Int64()),
		D: xdr.Int32(d.Num().Int64()),
	}, nil
}
				It("sets values properly", func() {
					builder := CreateOffer(rate, "20")

					Expect(builder.MO.Amount).To(Equal(xdr.Int64(200000000)))

					Expect(builder.MO.Selling.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum4))
					Expect(builder.MO.Selling.AlphaNum4.AssetCode).To(Equal([4]byte{'E', 'U', 'R', 0}))
					aid, _ := stellarbase.AddressToAccountId(rate.Selling.Issuer)
					Expect(builder.MO.Selling.AlphaNum4.Issuer.MustEd25519()).To(Equal(aid.MustEd25519()))
					Expect(builder.MO.Selling.AlphaNum12).To(BeNil())

					Expect(builder.MO.Buying.Type).To(Equal(xdr.AssetTypeAssetTypeNative))
					Expect(builder.MO.Buying.AlphaNum4).To(BeNil())
					Expect(builder.MO.Buying.AlphaNum12).To(BeNil())

					Expect(builder.MO.Price.N).To(Equal(xdr.Int32(8253)))
					Expect(builder.MO.Price.D).To(Equal(xdr.Int32(200)))

					Expect(builder.MO.OfferId).To(Equal(xdr.Uint64(0)))
				})
			})
		})

		Describe("UpdateOffer", func() {
			Context("updates the offer properly", func() {
				It("sets values properly", func() {
					builder := UpdateOffer(rate, "100", 5)

					Expect(builder.MO.Amount).To(Equal(xdr.Int64(1000000000)))

					Expect(builder.MO.Selling.Type).To(Equal(xdr.AssetTypeAssetTypeCreditAlphanum4))