// 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))