func (r BigRat) floatString(verb byte, prec int) string { switch verb { case 'f', 'F': return r.Rat.FloatString(prec) case 'e', 'E': // The exponent will alway be >= 0. sign := "" var x, t big.Rat x.Set(r.Rat) if x.Sign() < 0 { sign = "-" x.Neg(&x) } t.Set(&x) exp := ratExponent(&x) ratScale(&t, exp) str := t.FloatString(prec + 1) // +1 because first digit might be zero. // Drop the decimal. if str[0] == '0' { str = str[2:] exp-- } else if len(str) > 1 && str[1] == '.' { str = str[0:1] + str[2:] } return eFormat(verb, prec, sign, str, exp) case 'g', 'G': var x big.Rat x.Set(r.Rat) exp := ratExponent(&x) // Exponent could be positive or negative if exp < -4 || prec <= exp { // Use e format. verb -= 2 // g becomes e. return trimEZeros(verb, r.floatString(verb, prec-1)) } // Use f format. // If it's got zeros right of the decimal, they count as digits in the precision. // If it's got digits left of the decimal, they count as digits in the precision. // Both are handled by adjusting prec by exp. str := r.floatString(verb-1, prec-exp-1) // -1 for the one digit left of the decimal. // Trim trailing decimals. point := strings.IndexByte(str, '.') if point > 0 { n := len(str) for str[n-1] == '0' { n-- } str = str[:n] if str[n-1] == '.' { str = str[:n-1] } } return str default: Errorf("can't handle verb %c for rational", verb) } return "" }
// MulRat returns a new Currency value c = x * y, where y is a big.Rat. func (x Currency) MulRat(y *big.Rat) (c Currency) { if y.Sign() < 0 { build.Critical(ErrNegativeCurrency) } else { c.i.Mul(&x.i, y.Num()) c.i.Div(&c.i, y.Denom()) } return }
// MulRat returns a new Currency value c = x * y, where y is a big.Rat. func (x Currency) MulRat(y *big.Rat) (c Currency) { if y.Sign() < 0 { if build.DEBUG { panic(ErrNegativeCurrency) } } else { c.i.Mul(&x.i, y.Num()) c.i.Div(&c.i, y.Denom()) } return }
// Takes a transaction and balances it. This is mainly to fill in the empty part // with the remaining balance. func balanceTransaction(input *Transaction) error { balance := new(big.Rat) var emptyAccPtr *Account var emptyAccIndex int for accIndex, accChange := range input.AccountChanges { if accChange.Balance == nil { if emptyAccPtr != nil { return fmt.Errorf("More than one account change empty!") } emptyAccPtr = &accChange emptyAccIndex = accIndex } else { balance = balance.Add(balance, accChange.Balance) } } if balance.Sign() != 0 { if emptyAccPtr == nil { return fmt.Errorf("No empty account change to place extra balance!") } input.AccountChanges[emptyAccIndex].Balance = balance.Neg(balance) } return nil }
// ratExponent returns the power of ten that x would display in scientific notation. func ratExponent(x *big.Rat) int { if x.Sign() < 0 { x.Neg(x) } e := 0 invert := false if x.Num().Cmp(x.Denom()) < 0 { invert = true x.Inv(x) e++ } for x.Cmp(bigRatBillion) >= 0 { e += 9 x.Quo(x, bigRatBillion) } for x.Cmp(bigRatTen) > 0 { e++ x.Quo(x, bigRatTen) } if invert { return -e } return e }
// newComplex returns the smallest constant representation // for the specific value re + im*i; either an int64, *big.Int, // *big.Rat, or complex value. // func newComplex(re, im *big.Rat) interface{} { if im.Sign() == 0 { return normalizeRatConst(re) } return Complex{re, im} }
func normComplex(re, im *big.Rat) Value { if im.Sign() == 0 { return normFloat(re) } return complexVal{re, im} }