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 (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 "" }
func unaryFloatOp(x *big.Rat, op token.Token) interface{} { var z big.Rat switch op { case token.ADD: return z.Set(x) case token.SUB: return z.Neg(x) } panic("unreachable") }
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 }
// 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 }
//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 }
// Negate returns a *BigFloat that is the negative of n. func (n *BigFloat) Negate() Numeric { rat := new(big.Rat) return (*BigFloat)(rat.Neg((*big.Rat)(n))) }