// Total computes the Usage.Total() of all the Usages of a Basket func (b *Basket) Total() *big.Rat { total := new(big.Rat) for _, usage := range *b { total = total.Add(total, usage.Total()) } return total }
func EstimatePiFromPrevious(iteration, previousIndex int, sum *big.Rat) (*big.Rat, *big.Rat) { for i := previousIndex; i < iteration; i++ { sum.Add(sum, sn(i)) } pi := getPiFromSum(sum) return pi, sum }
func quo(x, y *complexRat) *complexRat { z := newComplexRat() denominator := new(big.Rat) t := new(big.Rat) t.Mul(y.r, y.r) denominator.Mul(y.i, y.i) denominator.Add(denominator, t) if denominator.Cmp(zero) == 0 { return newComplexRat() } ac := new(big.Rat) bd := new(big.Rat) ac.Mul(x.r, y.r) bd.Mul(x.i, y.i) bc := new(big.Rat) ad := new(big.Rat) bc.Mul(x.i, y.r) ad.Mul(x.r, y.i) z.r.Add(ac, bd) z.r.Quo(z.r, denominator) z.i.Add(bc, ad.Neg(ad)) z.i.Quo(z.i, denominator) return z }
func binaryFloatOp(x *big.Rat, op token.Token, y *big.Rat) interface{} { var z big.Rat switch op { case token.ADD: return z.Add(x, y) case token.SUB: return z.Sub(x, y) case token.MUL: return z.Mul(x, y) case token.QUO: return z.Quo(x, y) case token.EQL: return x.Cmp(y) == 0 case token.NEQ: return x.Cmp(y) != 0 case token.LSS: return x.Cmp(y) < 0 case token.LEQ: return x.Cmp(y) <= 0 case token.GTR: return x.Cmp(y) > 0 case token.GEQ: return x.Cmp(y) >= 0 } panic("unreachable") }
// Prints each transaction that matches the given filters. func PrintRegister(generalLedger []*ledger.Transaction, filterArr []string, columns int) { runningBalance := new(big.Rat) for _, trans := range generalLedger { for _, accChange := range trans.AccountChanges { inFilter := len(filterArr) == 0 for _, filter := range filterArr { if strings.Contains(accChange.Name, filter) { inFilter = true } } if inFilter { runningBalance.Add(runningBalance, accChange.Balance) writtenBytes, _ := fmt.Printf("%s %s", trans.Date.Format(ledger.TransactionDateFormat), trans.Payee) outBalanceString := accChange.Balance.FloatString(ledger.DisplayPrecision) outRunningBalanceString := runningBalance.FloatString(ledger.DisplayPrecision) spaceCount := columns - writtenBytes - 2 - len(outBalanceString) - len(outRunningBalanceString) if spaceCount < 0 { spaceCount = 0 } fmt.Printf("%s%s %s", strings.Repeat(" ", spaceCount), outBalanceString, outRunningBalanceString) fmt.Println("") } } } }
func renderRat(img *image.RGBA) { var yminR, ymaxMinR, heightR big.Rat yminR.SetInt64(ymin) ymaxMinR.SetInt64(ymax - ymin) heightR.SetInt64(height) var xminR, xmaxMinR, widthR big.Rat xminR.SetInt64(xmin) xmaxMinR.SetInt64(xmax - xmin) widthR.SetInt64(width) var y, x big.Rat for py := int64(0); py < height; py++ { // y := float64(py)/height*(ymax-ymin) + ymin y.SetInt64(py) y.Quo(&y, &heightR) y.Mul(&y, &ymaxMinR) y.Add(&y, &yminR) for px := int64(0); px < width; px++ { // x := float64(px)/width*(xmax-xmin) + xmin x.SetInt64(px) x.Quo(&x, &widthR) x.Mul(&x, &xmaxMinR) x.Add(&x, &xminR) c := mandelbrotRat(&x, &y) if c == nil { c = color.Black } img.Set(int(px), int(py), c) } } }
func cumulFlows(flows []*types.Flow) (bals []*types.Amount) { x := new(big.Rat) for _, f := range flows { x = x.Add(x, (*big.Rat)(f.Price)) bals = append(bals, new(types.Amount).SetRat(x)) } return }
func applyOp(val *big.Rat, op ast.OpClass, operand *big.Rat) { switch op { case ast.OpAdd: val.Add(val, operand) case ast.OpSubtract: val.Sub(val, operand) default: panic(fmt.Sprintf("eval.applyOp: unkown operand: %d (%s)", op, op)) } }
func Round(r *big.Rat) *big.Rat { d := new(big.Int).Set(r.Denom()) n := new(big.Int).Set(r.Num()) n.Mod(n, d) if new(big.Int).Mul(n, big.NewInt(2)).Cmp(d) >= 0 { r.Add(r, new(big.Rat).SetInt64(1)) } r.Sub(r, new(big.Rat).SetFrac(n, d)) return r }
func runBilling(cmd *Command, rawArgs []string) error { if billingHelp { return cmd.PrintUsage() } if len(rawArgs) > 0 { return cmd.PrintShortUsage() } // cli parsing args := commands.PsArgs{ NoTrunc: billingNoTrunc, } ctx := cmd.GetContext(rawArgs) logrus.Warn("") logrus.Warn("Warning: 'scw _billing' is a work-in-progress price estimation tool") logrus.Warn("For real usage, visit https://cloud.scaleway.com/#/billing") logrus.Warn("") // table w := tabwriter.NewWriter(ctx.Stdout, 20, 1, 3, ' ', 0) defer w.Flush() fmt.Fprintf(w, "ID\tNAME\tSTARTED\tMONTH PRICE\n") // servers servers, err := cmd.API.GetServers(true, 0) if err != nil { return err } totalMonthPrice := new(big.Rat) for _, server := range *servers { if server.State != "running" { continue } commercialType := strings.ToLower(server.CommercialType) shortID := utils.TruncIf(server.Identifier, 8, !args.NoTrunc) shortName := utils.TruncIf(utils.Wordify(server.Name), 25, !args.NoTrunc) modificationTime, _ := time.Parse("2006-01-02T15:04:05.000000+00:00", server.ModificationDate) modificationAgo := time.Now().UTC().Sub(modificationTime) shortModificationDate := units.HumanDuration(modificationAgo) usage := pricing.NewUsageByPath(fmt.Sprintf("/compute/%s/run", commercialType)) usage.SetStartEnd(modificationTime, time.Now().UTC()) totalMonthPrice = totalMonthPrice.Add(totalMonthPrice, usage.Total()) fmt.Fprintf(w, "server/%s/%s\t%s\t%s\t%s\n", commercialType, shortID, shortName, shortModificationDate, usage.TotalString()) } fmt.Fprintf(w, "TOTAL\t\t\t%s\n", pricing.PriceString(totalMonthPrice, "EUR")) return nil }
func (z *BigComplex) Mul(x, y *BigComplex) *BigComplex { re := new(big.Rat).Mul(&x.Re, &y.Re) re.Sub(re, new(big.Rat).Mul(&x.Im, &y.Im)) im := new(big.Rat).Mul(&x.Re, &y.Im) im.Add(im, new(big.Rat).Mul(&x.Im, &y.Re)) z.Re = *re z.Im = *im return z }
func (v1 Vector) Dot(v2 Vector) *big.Rat { if len(v1) != len(v2) { log.Fatalf("Lengths differ: %d != %d", len(v1), len(v2)) } d := new(big.Rat) c := new(big.Rat) for i, e := range v1 { d.Add(d, c.Mul(e, v2[i])) } return d }
func Newt_Sqrt(a *big.Rat, x *big.Rat) *big.Rat { for i := 0; i < 12; i++ { var quot1 = big.NewRat(1, 1) quot1 = quot1.Quo(x, big.NewRat(2, 1)) var mul = big.NewRat(1, 1) mul = mul.Mul(big.NewRat(2, 1), x) var quot2 = big.NewRat(1, 1) quot2 = quot2.Quo(a, mul) x = x.Add(quot1, quot2) } return x }
func abs(x *complexRat) *big.Rat { r := new(big.Rat) i := new(big.Rat) r.Set(x.r) i.Set(x.i) r.Mul(r, x.r) // r^2 i.Mul(i, x.i) // i^2 r.Add(r, i) // r^2 + i^2 return sqrtFloat(r) // sqrt(r^2 + i^2) }
func sexToDec(deg, min, sec *big.Rat, dir string) *big.Rat { // sexagesimal (base 60) to decimal // https://imm.dtf.wa.gov.au/helpfiles/Latitude_Longitude_conversion_hlp.htm deg.Add(deg, min.Quo(min, big.NewRat(60, 1))) deg.Add(deg, sec.Quo(sec, big.NewRat(3600, 1))) // N and E are the positive directions (like on an x,y axis) if dir == "S" || dir == "W" { deg.Neg(deg) } return deg }
func binaryCmplxOp(x cmplx, op token.Token, y cmplx) interface{} { a, b := x.re, x.im c, d := y.re, y.im switch op { case token.ADD: // (a+c) + i(b+d) var re, im big.Rat re.Add(a, c) im.Add(b, d) return cmplx{&re, &im} case token.SUB: // (a-c) + i(b-d) var re, im big.Rat re.Sub(a, c) im.Sub(b, d) return cmplx{&re, &im} case token.MUL: // (ac-bd) + i(bc+ad) var ac, bd, bc, ad big.Rat ac.Mul(a, c) bd.Mul(b, d) bc.Mul(b, c) ad.Mul(a, d) var re, im big.Rat re.Sub(&ac, &bd) im.Add(&bc, &ad) return cmplx{&re, &im} case token.QUO: // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd var ac, bd, bc, ad, s big.Rat ac.Mul(a, c) bd.Mul(b, d) bc.Mul(b, c) ad.Mul(a, d) s.Add(c.Mul(c, c), d.Mul(d, d)) var re, im big.Rat re.Add(&ac, &bd) re.Quo(&re, &s) im.Sub(&bc, &ad) im.Quo(&im, &s) return cmplx{&re, &im} case token.EQL: return a.Cmp(c) == 0 && b.Cmp(d) == 0 case token.NEQ: return a.Cmp(c) != 0 || b.Cmp(d) != 0 } panic("unreachable") }
func sqrtFloat(x *big.Rat) *big.Rat { t1 := new(big.Rat) t2 := new(big.Rat) t1.Set(x) // Iterate. // x{n} = (x{n-1}+x{0}/x{n-1}) / 2 for i := 0; i <= 4; i++ { if t1.Cmp(zero) == 0 { return t1 } t2.Quo(x, t1) t2.Add(t2, t1) t1.Mul(half, t2) } return t1 }
// Prints out account balances formated to a windows of a width of columns. // Only shows accounts with names less than or equal to the given depth. func PrintBalances(accountList []*ledger.Account, printZeroBalances bool, depth, columns int) { overallBalance := new(big.Rat) for _, account := range accountList { accDepth := len(strings.Split(account.Name, ":")) if accDepth == 1 { overallBalance.Add(overallBalance, account.Balance) } if (printZeroBalances || account.Balance.Sign() != 0) && (depth < 0 || accDepth <= depth) { outBalanceString := account.Balance.FloatString(ledger.DisplayPrecision) spaceCount := columns - len(account.Name) - len(outBalanceString) fmt.Printf("%s%s%s\n", account.Name, strings.Repeat(" ", spaceCount), outBalanceString) } } fmt.Println(strings.Repeat("-", columns)) outBalanceString := overallBalance.FloatString(ledger.DisplayPrecision) spaceCount := columns - len(outBalanceString) fmt.Printf("%s%s\n", strings.Repeat(" ", spaceCount), outBalanceString) }
// Use the classic continued fraction for e // e = [1; 0, 1, 1, 2, 1, 1, ... 2n, 1, 1, ...] // i.e., for the nth term, use // 1 if n mod 3 != 1 // (n-1)/3 * 2 if n mod 3 == 1 func recur(n, lim int64) *big.Rat { term := new(big.Rat) if n%3 != 1 { term.SetInt64(1) } else { term.SetInt64((n - 1) / 3 * 2) } if n > lim { return term } // Directly initialize frac as the fractional // inverse of the result of recur. frac := new(big.Rat).Inv(recur(n+1, lim)) return term.Add(term, frac) }
func mandelbrotRat(a, b *big.Rat) color.Color { var x, y, nx, ny, x2, y2, f2, f4, r2, tmp big.Rat f2.SetInt64(2) f4.SetInt64(4) x.SetInt64(0) y.SetInt64(0) defer func() { recover() }() for n := uint8(0); n < iterations; n++ { // Not update x2 and y2 // because they are already updated in the previous loop nx.Sub(&x2, &y2) nx.Add(&nx, a) tmp.Mul(&x, &y) ny.Mul(&f2, &tmp) ny.Add(&ny, b) x.Set(&nx) y.Set(&ny) x2.Mul(&x, &x) y2.Mul(&y, &y) r2.Add(&x2, &y2) if r2.Cmp(&f4) > 0 { return color.Gray{255 - contrast*n} } } return color.Black }
func eDigits(precisionFactor int, stringLength int) string { array := make([]int64, precisionFactor) for i := 0; i < precisionFactor; i++ { var t int64 = int64(i) array[i] = t + 1 } var digitsToMultiply []int64 var e *big.Rat = big.NewRat(1, 1) for i := 1; i <= precisionFactor; i++ { digitsToMultiply = array[0:i] var digitsProduct int64 = 1 for x := 0; x < len(digitsToMultiply); x++ { digitsProduct = digitsProduct * digitsToMultiply[x] } var finalProduct *big.Rat = big.NewRat(1, digitsProduct) e.Add(e, finalProduct) } return e.FloatString(stringLength) }
// Check the transaction to ensure it is balanced func (t *Transaction) CheckBalance() error { if len(t.Accounts) == 0 { return errors.New("Transaction does not have any accounts") } // Check that they balance balance := new(big.Rat) for _, a := range t.Accounts { if a.Debit { balance.Add(balance, a.Amount) } else { balance.Sub(balance, a.Amount) } } b := balance.FloatString(2) if b != "0.00" { return errors.New(fmt.Sprintf("Transaction does not balance: %s", b)) } return nil }
// PrintRegister prints each transaction that matches the given filters. func PrintRegister(generalLedger []*ledger.Transaction, filterArr []string, columns int) { // Calulate widths for variable-length part of output // 3 10-width columns (date, account-change, running-total) // 4 spaces remainingWidth := columns - (10 * 3) - (4 * 1) formatString := fmt.Sprintf("%%-10.10s %%-%[1]d.%[1]ds %%-%[2]d.%[2]ds %%10.10s %%10.10s\n", remainingWidth/3, (remainingWidth/3)*2) var otherAccount string runningBalance := new(big.Rat) for _, trans := range generalLedger { for aIdx, accChange := range trans.AccountChanges { inFilter := len(filterArr) == 0 for _, filter := range filterArr { if strings.Contains(accChange.Name, filter) { inFilter = true // Probably not the best way, but we just need to find one other account if aIdx > 0 { otherAccount = trans.AccountChanges[0].Name } else { otherAccount = trans.AccountChanges[1].Name } } } if inFilter { runningBalance.Add(runningBalance, accChange.Balance) outBalanceString := accChange.Balance.FloatString(displayPrecision) outRunningBalanceString := runningBalance.FloatString(displayPrecision) fmt.Printf(formatString, trans.Date.Format(transactionDateFormat), trans.Payee, otherAccount, outBalanceString, outRunningBalanceString) } } } }
// 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 }
// How many fractions contain a numerator with more digits than the denominator? func problem57() int { sum := 0 // Number of fractions meeting the description. const limit = 1000 // Given in problem description. one := new(big.Rat).SetInt64(1) two := new(big.Rat).SetInt64(2) // result will be re-used each iteration to store the // current value of the fractional expansion. result := new(big.Rat) // tail will be re-used each iteration to store the // current value of the repeating component of the expansion. // That component is 2, (2 + 1/2), (2 + 1/(2 + 1/2)), ... tail := new(big.Rat).SetInt64(2) for i := 0; i < limit; i++ { temp := new(big.Rat) tail.Add(two, temp.Inv(tail)) // tail = (2 + 1/tail) result.Add(one, temp.Inv(tail)) // result = (1 + 1/tail) if checkNumerator(result) { sum++ } } return sum }
//export OFXTransactionCallback func OFXTransactionCallback(transaction_data C.struct_OfxTransactionData, data unsafe.Pointer) C.int { iobj := (*ImportObject)(data) itl := iobj.TransactionList transaction := new(Transaction) if transaction_data.name_valid != 0 { transaction.Description = C.GoString(&transaction_data.name[0]) } // if transaction_data.reference_number_valid != 0 { // fmt.Println("reference_number: ", C.GoString(&transaction_data.reference_number[0])) // } if transaction_data.date_posted_valid != 0 { transaction.Date = time.Unix(int64(transaction_data.date_posted), 0) } else if transaction_data.date_initiated_valid != 0 { transaction.Date = time.Unix(int64(transaction_data.date_initiated), 0) } if transaction_data.fi_id_valid != 0 { transaction.RemoteId = C.GoString(&transaction_data.fi_id[0]) } if transaction_data.amount_valid != 0 { split := new(Split) r := new(big.Rat) r.SetFloat64(float64(transaction_data.amount)) security, err := GetSecurity(itl.Account.SecurityId, itl.Account.UserId) if err != nil { if iobj.Error == nil { iobj.Error = err } return 1 } split.Amount = r.FloatString(security.Precision) if transaction_data.memo_valid != 0 { split.Memo = C.GoString(&transaction_data.memo[0]) } if transaction_data.check_number_valid != 0 { split.Number = C.GoString(&transaction_data.check_number[0]) } split.SecurityId = -1 split.AccountId = itl.Account.AccountId transaction.Splits = append(transaction.Splits, split) } else { if iobj.Error == nil { iobj.Error = errors.New("OFX transaction amount invalid") } return 1 } var security *Security var err error split := new(Split) units := new(big.Rat) if transaction_data.units_valid != 0 { units.SetFloat64(float64(transaction_data.units)) if transaction_data.security_data_valid != 0 { security_data := transaction_data.security_data_ptr if security_data.ticker_valid != 0 { s, err := GetSecurityByName(C.GoString(&security_data.ticker[0])) if err != nil { if iobj.Error == nil { iobj.Error = errors.New("Failed to find OFX transaction security: " + C.GoString(&security_data.ticker[0])) } return 1 } security = s } else { if iobj.Error == nil { iobj.Error = errors.New("OFX security ticker invalid") } return 1 } if security.Type == Stock && security_data.unique_id_valid != 0 && security_data.unique_id_type_valid != 0 && C.GoString(&security_data.unique_id_type[0]) == "CUSIP" { // Validate the security CUSIP, if possible if security.AlternateId != C.GoString(&security_data.unique_id[0]) { if iobj.Error == nil { iobj.Error = errors.New("OFX transaction security CUSIP failed to validate") } return 1 } } } else { security, err = GetSecurity(itl.Account.SecurityId, itl.Account.UserId) if err != nil { if iobj.Error == nil { iobj.Error = err } return 1 } } } else { // Calculate units from other available fields if its not present // units = - (amount + various fees) / unitprice units.SetFloat64(float64(transaction_data.amount)) fees := new(big.Rat) if transaction_data.fees_valid != 0 { fees.SetFloat64(float64(-transaction_data.fees)) } if transaction_data.commission_valid != 0 { commission := new(big.Rat) commission.SetFloat64(float64(-transaction_data.commission)) fees.Add(fees, commission) } units.Add(units, fees) units.Neg(units) if transaction_data.unitprice_valid != 0 && transaction_data.unitprice != 0 { unitprice := new(big.Rat) unitprice.SetFloat64(float64(transaction_data.unitprice)) units.Quo(units, unitprice) } // If 'units' wasn't present, assume we're using the account's security security, err = GetSecurity(itl.Account.SecurityId, itl.Account.UserId) if err != nil { if iobj.Error == nil { iobj.Error = err } return 1 } } split.Amount = units.FloatString(security.Precision) split.SecurityId = security.SecurityId split.AccountId = -1 transaction.Splits = append(transaction.Splits, split) if transaction_data.fees_valid != 0 { split := new(Split) r := new(big.Rat) r.SetFloat64(float64(-transaction_data.fees)) security, err := GetSecurity(itl.Account.SecurityId, itl.Account.UserId) if err != nil { if iobj.Error == nil { iobj.Error = err } return 1 } split.Amount = r.FloatString(security.Precision) split.Memo = "fees" split.SecurityId = itl.Account.SecurityId split.AccountId = -1 transaction.Splits = append(transaction.Splits, split) } if transaction_data.commission_valid != 0 { split := new(Split) r := new(big.Rat) r.SetFloat64(float64(-transaction_data.commission)) security, err := GetSecurity(itl.Account.SecurityId, itl.Account.UserId) if err != nil { if iobj.Error == nil { iobj.Error = err } return 1 } split.Amount = r.FloatString(security.Precision) split.Memo = "commission" split.SecurityId = itl.Account.SecurityId split.AccountId = -1 transaction.Splits = append(transaction.Splits, split) } // if transaction_data.payee_id_valid != 0 { // fmt.Println("payee_id: ", C.GoString(&transaction_data.payee_id[0])) // } transaction_list := append(*itl.Transactions, *transaction) iobj.TransactionList.Transactions = &transaction_list return 0 }
// BinaryOp returns the result of the binary expression x op y. // The operation must be defined for the operands. // To force integer division of Int operands, use op == token.QUO_ASSIGN // instead of token.QUO; the result is guaranteed to be Int in this case. // Division by zero leads to a run-time panic. // func BinaryOp(x Value, op token.Token, y Value) Value { x, y = match(x, y) switch x := x.(type) { case unknownVal: return x case boolVal: y := y.(boolVal) switch op { case token.LAND: return x && y case token.LOR: return x || y } case int64Val: a := int64(x) b := int64(y.(int64Val)) var c int64 switch op { case token.ADD: if !is63bit(a) || !is63bit(b) { return normInt(new(big.Int).Add(big.NewInt(a), big.NewInt(b))) } c = a + b case token.SUB: if !is63bit(a) || !is63bit(b) { return normInt(new(big.Int).Sub(big.NewInt(a), big.NewInt(b))) } c = a - b case token.MUL: if !is32bit(a) || !is32bit(b) { return normInt(new(big.Int).Mul(big.NewInt(a), big.NewInt(b))) } c = a * b case token.QUO: return normFloat(new(big.Rat).SetFrac(big.NewInt(a), big.NewInt(b))) case token.QUO_ASSIGN: // force integer division c = a / b case token.REM: c = a % b case token.AND: c = a & b case token.OR: c = a | b case token.XOR: c = a ^ b case token.AND_NOT: c = a &^ b default: goto Error } return int64Val(c) case intVal: a := x.val b := y.(intVal).val var c big.Int switch op { case token.ADD: c.Add(a, b) case token.SUB: c.Sub(a, b) case token.MUL: c.Mul(a, b) case token.QUO: return normFloat(new(big.Rat).SetFrac(a, b)) case token.QUO_ASSIGN: // force integer division c.Quo(a, b) case token.REM: c.Rem(a, b) case token.AND: c.And(a, b) case token.OR: c.Or(a, b) case token.XOR: c.Xor(a, b) case token.AND_NOT: c.AndNot(a, b) default: goto Error } return normInt(&c) case floatVal: a := x.val b := y.(floatVal).val var c big.Rat switch op { case token.ADD: c.Add(a, b) case token.SUB: c.Sub(a, b) case token.MUL: c.Mul(a, b) case token.QUO: c.Quo(a, b) default: goto Error } return normFloat(&c) case complexVal: y := y.(complexVal) a, b := x.re, x.im c, d := y.re, y.im var re, im big.Rat switch op { case token.ADD: // (a+c) + i(b+d) re.Add(a, c) im.Add(b, d) case token.SUB: // (a-c) + i(b-d) re.Sub(a, c) im.Sub(b, d) case token.MUL: // (ac-bd) + i(bc+ad) var ac, bd, bc, ad big.Rat ac.Mul(a, c) bd.Mul(b, d) bc.Mul(b, c) ad.Mul(a, d) re.Sub(&ac, &bd) im.Add(&bc, &ad) case token.QUO: // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd var ac, bd, bc, ad, s, cc, dd big.Rat ac.Mul(a, c) bd.Mul(b, d) bc.Mul(b, c) ad.Mul(a, d) cc.Mul(c, c) dd.Mul(d, d) s.Add(&cc, &dd) re.Add(&ac, &bd) re.Quo(&re, &s) im.Sub(&bc, &ad) im.Quo(&im, &s) default: goto Error } return normComplex(&re, &im) case stringVal: if op == token.ADD { return x + y.(stringVal) } } Error: panic(fmt.Sprintf("invalid binary operation %v %s %v", x, op, y)) }
// binaryOpConst returns the result of the constant evaluation x op y; // both operands must be of the same "kind" (boolean, numeric, or string). // If intDiv is true, division (op == token.QUO) is using integer division // (and the result is guaranteed to be integer) rather than floating-point // division. Division by zero leads to a run-time panic. // func binaryOpConst(x, y interface{}, op token.Token, intDiv bool) interface{} { x, y = matchConst(x, y) switch x := x.(type) { case bool: y := y.(bool) switch op { case token.LAND: return x && y case token.LOR: return x || y default: unreachable() } case int64: y := y.(int64) switch op { case token.ADD: // TODO(gri) can do better than this if is63bit(x) && is63bit(y) { return x + y } return normalizeIntConst(new(big.Int).Add(big.NewInt(x), big.NewInt(y))) case token.SUB: // TODO(gri) can do better than this if is63bit(x) && is63bit(y) { return x - y } return normalizeIntConst(new(big.Int).Sub(big.NewInt(x), big.NewInt(y))) case token.MUL: // TODO(gri) can do better than this if is32bit(x) && is32bit(y) { return x * y } return normalizeIntConst(new(big.Int).Mul(big.NewInt(x), big.NewInt(y))) case token.REM: return x % y case token.QUO: if intDiv { return x / y } return normalizeRatConst(new(big.Rat).SetFrac(big.NewInt(x), big.NewInt(y))) case token.AND: return x & y case token.OR: return x | y case token.XOR: return x ^ y case token.AND_NOT: return x &^ y default: unreachable() } case *big.Int: y := y.(*big.Int) var z big.Int switch op { case token.ADD: z.Add(x, y) case token.SUB: z.Sub(x, y) case token.MUL: z.Mul(x, y) case token.REM: z.Rem(x, y) case token.QUO: if intDiv { z.Quo(x, y) } else { return normalizeRatConst(new(big.Rat).SetFrac(x, y)) } case token.AND: z.And(x, y) case token.OR: z.Or(x, y) case token.XOR: z.Xor(x, y) case token.AND_NOT: z.AndNot(x, y) default: unreachable() } return normalizeIntConst(&z) case *big.Rat: y := y.(*big.Rat) var z big.Rat switch op { case token.ADD: z.Add(x, y) case token.SUB: z.Sub(x, y) case token.MUL: z.Mul(x, y) case token.QUO: z.Quo(x, y) default: unreachable() } return normalizeRatConst(&z) case complex: y := y.(complex) a, b := x.re, x.im c, d := y.re, y.im var re, im big.Rat switch op { case token.ADD: // (a+c) + i(b+d) re.Add(a, c) im.Add(b, d) case token.SUB: // (a-c) + i(b-d) re.Sub(a, c) im.Sub(b, d) case token.MUL: // (ac-bd) + i(bc+ad) var ac, bd, bc, ad big.Rat ac.Mul(a, c) bd.Mul(b, d) bc.Mul(b, c) ad.Mul(a, d) re.Sub(&ac, &bd) im.Add(&bc, &ad) case token.QUO: // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd var ac, bd, bc, ad, s big.Rat ac.Mul(a, c) bd.Mul(b, d) bc.Mul(b, c) ad.Mul(a, d) s.Add(c.Mul(c, c), d.Mul(d, d)) re.Add(&ac, &bd) re.Quo(&re, &s) im.Sub(&bc, &ad) im.Quo(&im, &s) default: unreachable() } return normalizeComplexConst(complex{&re, &im}) case string: if op == token.ADD { return x + y.(string) } } unreachable() return nil }
// evaluatePostfix takes a postfix expression and evaluates it func evaluatePostfix(postfix []string) (*big.Rat, error) { var stack stack.Stack result := new(big.Rat) // note: a new(big.Rat) has value "0/1" ie zero for _, token := range postfix { if isOperand(token) { bigrat := new(big.Rat) if _, err := fmt.Sscan(token, bigrat); err != nil { return nil, fmt.Errorf("unable to scan %s", token) } stack.Push(bigrat) } else if isOperator(token) { op2, err2 := stack.Pop() if err2 != nil { return nil, err2 } var op1 interface{} if token != "@" { var err1 error if op1, err1 = stack.Pop(); err1 != nil { return nil, err1 } } dummy := new(big.Rat) switch token { case "**": float1 := BigratToFloat(op1.(*big.Rat)) float2 := BigratToFloat(op2.(*big.Rat)) float_result := math.Pow(float1, float2) stack.Push(FloatToBigrat(float_result)) case "*": result := dummy.Mul(op1.(*big.Rat), op2.(*big.Rat)) stack.Push(result) case "/": result := dummy.Quo(op1.(*big.Rat), op2.(*big.Rat)) stack.Push(result) case "+": result = dummy.Add(op1.(*big.Rat), op2.(*big.Rat)) stack.Push(result) case "-": result = dummy.Sub(op1.(*big.Rat), op2.(*big.Rat)) stack.Push(result) case "<": if op1.(*big.Rat).Cmp(op2.(*big.Rat)) <= -1 { stack.Push(big.NewRat(1, 1)) } else { stack.Push(new(big.Rat)) } case ">": if op1.(*big.Rat).Cmp(op2.(*big.Rat)) >= 1 { stack.Push(big.NewRat(1, 1)) } else { stack.Push(new(big.Rat)) } case "@": result := dummy.Mul(big.NewRat(-1, 1), op2.(*big.Rat)) stack.Push(result) } } else { return nil, fmt.Errorf("unknown token %v", token) } } retval, err := stack.Pop() if err != nil { return nil, err } return retval.(*big.Rat), nil }
func (a *EqualSplitsAlgorithm) generateBoundaries() ([]tuple, error) { // generateBoundaries should work for a split_column whose type is integral // (both signed and unsigned) as well as for floating point values. // We perform the calculation of the boundaries using precise big.Rat arithmetic and only // truncate the result in the end if necessary. // We do this since using float64 arithmetic does not have enough precision: // for example, if max=math.MaxUint64 and min=math.MaxUint64-1000 then float64(min)==float64(max). // On the other hand, using integer arithmetic for the case where the split_column is integral // (i.e., rounding (max-min)/split_count to an integer) may cause very dissimilar interval // lengths or a large deviation between split_count and the number of query-parts actually // returned (consider min=0, max=9.5*10^6, and split_count=10^6). // Note(erez): We can probably get away with using big.Float with ~64 bits of precision which // will likely be more efficient. However, we defer optimizing this code until we see if this // is a bottle-neck. minValue, maxValue, err := a.executeMinMaxQuery() if err != nil { return nil, err } // If the table is empty, minValue and maxValue will be NULL. if (minValue.IsNull() && !maxValue.IsNull()) || !minValue.IsNull() && maxValue.IsNull() { panic(fmt.Sprintf("minValue and maxValue must both be NULL or both be non-NULL."+ " minValue: %v, maxValue: %v, splitParams.sql: %v", minValue, maxValue, a.splitParams.sql)) } if minValue.IsNull() { log.Infof("Splitting an empty table. splitParams.sql: %v. Query will not be split.", a.splitParams.sql) return []tuple{}, nil } min, err := valueToBigRat(minValue) if err != nil { panic(fmt.Sprintf("Failed to convert min to a big.Rat: %v, min: %+v", err, min)) } max, err := valueToBigRat(maxValue) if err != nil { panic(fmt.Sprintf("Failed to convert max to a big.Rat: %v, max: %+v", err, max)) } minCmpMax := min.Cmp(max) if minCmpMax > 0 { panic(fmt.Sprintf("max(splitColumn) < min(splitColumn): max:%v, min:%v", max, min)) } if minCmpMax == 0 { log.Infof("max(%v)=min(%v)=%v. splitParams.sql: %v. Query will not be split.", a.splitParams.splitColumns[0], a.splitParams.splitColumns[0], min, a.splitParams.sql) return []tuple{}, nil } // subIntervalSize = (max - min) / a.splitParams.splitCount subIntervalSize := new(big.Rat) subIntervalSize.Sub(max, min) subIntervalSize.Quo(subIntervalSize, new(big.Rat).SetInt64(a.splitParams.splitCount)) boundary := new(big.Rat).Set(min) // Copy min into boundary. var result []tuple for i := int64(1); i < a.splitParams.splitCount; i++ { boundary.Add(boundary, subIntervalSize) // Here boundary=min+i*subIntervalSize boundaryValue := bigRatToValue(boundary, a.splitParams.splitColumnTypes[0]) result = append(result, tuple{boundaryValue}) } return result, nil }