Ejemplo n.º 1
0
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")
}
Ejemplo n.º 2
0
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
}
Ejemplo n.º 3
0
func convertMeasure(in Measure) string {
	if in == Measure(0) {
		return "0"
	}
	measureNamesKeys := []int{}

	for m := range measureNames {
		measureNamesKeys = append(measureNamesKeys, int(m))
	}

	sort.Ints(measureNamesKeys)
	inInt := int(in)
	_ = inInt
	for i := len(measureNamesKeys) - 1; i >= 0; i-- {
		key := measureNamesKeys[i]

		if inInt > key {
			a := big.NewRat(int64(inInt), 256)
			b := measureNames[Measure(key)].Rat
			r := new(big.Rat)
			s := r.Sub(a, b)
			return b.RatString() + " + " + s.RatString()
		}
	}
	return "not found"
}
Ejemplo n.º 4
0
Archivo: eval.go Proyecto: albrow/calc
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))
	}
}
Ejemplo n.º 5
0
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 tans(m []mTerm) *big.Rat {
	if len(m) == 1 {
		return tanEval(m[0].a, big.NewRat(m[0].n, m[0].d))
	}
	half := len(m) / 2
	a := tans(m[:half])
	b := tans(m[half:])
	r := new(big.Rat)
	return r.Quo(new(big.Rat).Add(a, b), r.Sub(one, r.Mul(a, b)))
}
Ejemplo n.º 7
0
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 tanEval(coef int64, f *big.Rat) *big.Rat {
	if coef == 1 {
		return f
	}
	if coef < 0 {
		r := tanEval(-coef, f)
		return r.Neg(r)
	}
	ca := coef / 2
	cb := coef - ca
	a := tanEval(ca, f)
	b := tanEval(cb, f)
	r := new(big.Rat)
	return r.Quo(new(big.Rat).Add(a, b), r.Sub(one, r.Mul(a, b)))
}
func main() {
	ln2, _ := new(big.Rat).SetString("0.6931471805599453094172")
	h := big.NewRat(1, 2)
	h.Quo(h, ln2)
	var f big.Rat
	var w big.Int
	for i := int64(1); i <= 17; i++ {
		h.Quo(h.Mul(h, f.SetInt64(i)), ln2)
		w.Quo(h.Num(), h.Denom())
		f.Sub(h, f.SetInt(&w))
		y, _ := f.Float64()
		d := fmt.Sprintf("%.3f", y)
		fmt.Printf("n: %2d  h: %18d%s  Nearly integer: %t\n",
			i, &w, d[1:], d[2] == '0' || d[2] == '9')
	}
}
func (me *StatisticalAccumulator) Variance() *big.Rat {
	variance := new(big.Rat)

	variance.Inv(me.n)

	variance.Mul(variance, me.sigmaXISquared)

	temp := new(big.Rat)

	temp.Mul(me.n, me.n)
	temp.Inv(temp)

	temp.Mul(temp, me.sigmaXI)
	temp.Mul(temp, me.sigmaXI)

	variance.Sub(variance, temp)

	return variance
}
Ejemplo n.º 11
0
// 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
}
Ejemplo n.º 12
0
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")
}
Ejemplo n.º 13
0
// 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
}
Ejemplo n.º 14
0
// 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
}
Ejemplo n.º 15
0
func main() {
	f, err := os.Create("/tmp/profile")
	if err != nil {
		log.Fatal(err)
	}
	pprof.StartCPUProfile(f)
	defer pprof.StopCPUProfile()

	p, _ := new(big.Int).SetString("233970423115425145524320034830162017933", 10)
	a := big.NewInt(-95051)
	b := big.NewInt(11279326)
	G := dh.NewEllipticCurve(a, b, p)

	gx := big.NewInt(182)
	gy, _ := new(big.Int).SetString("85518893674295321206118380980485522083", 10)
	g := dh.NewEllipticCurveElement(G, gx, gy)
	q, _ := new(big.Int).SetString("29246302889428143187362802287225875743", 10)
	GG := dh.NewGeneratedGroup(G, g, *q)

	var bias uint = 8
	alice := dh.NewBiasedECDSA(GG, bias)

	var msg = []byte("I was a fiend")
	key, _ := new(big.Int).SetString("255bf9c75628ab469b45cced58755a3", 16)
	d := new(big.Rat).SetInt(key)

	numSigs := 22
	B := dh.Matrix(make([]dh.Vector, numSigs+2))
	zero := dh.Vector(make([]*big.Rat, numSigs+2))
	for i, _ := range zero {
		zero[i] = new(big.Rat)
	}
	for i, _ := range B {
		B[i] = zero.Copy()
	}
	ct := big.NewRat(1, 1<<bias)
	B[len(B)-2][len(B)-2].Set(ct)
	cu := new(big.Rat).SetInt(q)
	cu.Quo(cu, big.NewRat(1<<bias, 1))
	B[len(B)-1][len(B)-1].Set(cu)
	ts := make([]*big.Int, numSigs)
	us := make([]*big.Int, numSigs)
	for i := 0; i < numSigs; i++ {
		B[i][i].SetInt(q)
		r, s := alice.Sign(msg)
		t, u := transform(msg, r, s, q, bias)
		dt := new(big.Int).Mul(key, t)
		temp := new(big.Int).Sub(u, dt)
		temp.Mod(temp, q)
		temp.Sub(q, temp)
		log.Printf("\ndt:     %x\nu:      %x\nq-u-dt: %x\nq:      %x", dt, u, temp, q)
		ts[i] = t
		us[i] = u
		B[len(B)-2][i] = new(big.Rat).SetInt(t)
		B[len(B)-1][i] = new(big.Rat).SetInt(u)
	}

	check := B[len(B)-1].Copy()
	check.Sub(B[len(B)-2].Copy().Scale(d))
	for i := 0; i < numSigs; i++ {
		t := ts[i]
		dt := new(big.Int).Mul(key, t)
		m := new(big.Int).Div(dt, q)
		check.Add(B[i].Copy().Scale(new(big.Rat).SetInt(m)))
	}
	log.Printf("check=%s", check)

	B.LLL(big.NewRat(99, 100))

	for _, v := range B {
		if v[len(v)-1].Cmp(cu) == 0 {
			log.Printf("%s", v)
			d := new(big.Rat)
			d.Sub(d, v[len(v)-2])
			d.Mul(d, big.NewRat(1<<bias, 1))
			guess := dh.Round(d).Num()
			log.Printf("Recovered key: %x", guess)
			log.Printf("Correct: %v", guess.Cmp(key) == 0)
		}
	}
}
func backsub(m Matrix) (Vector, error) {
	if len(m) == 0 || len(m[0]) < 2 {
		return Vector{}, nil
	}

	coeffs := make(Vector, len(m[0])-1)
	cnts := make([]int, len(m))
	for i := range cnts {
		cnts[i] = -1
	}

	zero := new(big.Rat)
	for i := range m {
		nz := 0
		l := len(m[i]) - 1
		for j := range m[i][:l] {
			if m[i][j].Cmp(zero) != 0 {
				nz++
			}
		}
		if l-nz == l {
			return nil, fmt.Errorf("contains a zero row")
		}
		cnts[i] = nz
	}

	z := make([]index, len(cnts))
	for i := range z {
		z[i].r = i
		z[i].n = cnts[i]
	}
	sort.Sort(indexSlice(z))

	for i := range z {
		r := m[z[i].r]
		l := len(r) - 1
		w := new(big.Rat).Set(r[l])

		var v *big.Rat
		for j := range r[:l] {
			if r[j].Cmp(zero) == 0 {
				continue
			}

			if coeffs[j] != nil {
				u := new(big.Rat).Set(coeffs[j])
				u.Mul(u, r[j])
				w.Sub(w, u)
			} else if v != nil {
				return nil, fmt.Errorf("matrix not in rref form")
			} else {
				v = new(big.Rat).Set(r[j])
			}
		}
		if v.Cmp(zero) == 0 {
			return nil, fmt.Errorf("matrix not in rref form")
		}
		coeffs[z[i].r] = w.Quo(w, v)
	}

	return coeffs, nil
}
Ejemplo n.º 17
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))
}
Ejemplo n.º 18
0
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
}