Example #1
0
// TODO(austin): Maybe add to bignum in more general form
func ratToString(rat *bignum.Rational) string {
	n, dnat := rat.Value()
	d := bignum.MakeInt(false, dnat)
	w, frac := n.QuoRem(d)
	out := w.String()
	if frac.IsZero() {
		return out
	}

	r := frac.Abs()
	r = r.Mul(bignum.Nat(1e6))
	dec, tail := r.DivMod(dnat)
	// Round last digit
	if tail.Cmp(dnat.Div(bignum.Nat(2))) >= 0 {
		dec = dec.Add(bignum.Nat(1))
	}
	// Strip zeros
	ten := bignum.Nat(10)
	for !dec.IsZero() {
		dec2, r2 := dec.DivMod(ten)
		if !r2.IsZero() {
			break
		}
		dec = dec2
	}
	out += "." + dec.String()
	return out
}
Example #2
0
// a.convertTo(t) converts the value of the analyzed expression a,
// which must be a constant, ideal number, to a new analyzed
// expression with a constant value of type t.
//
// TODO(austin) Rename to resolveIdeal or something?
func (a *expr) convertTo(t Type) *expr {
	if !a.t.isIdeal() {
		log.Crashf("attempted to convert from %v, expected ideal", a.t)
	}

	var rat *bignum.Rational

	// XXX(Spec)  The spec says "It is erroneous".
	//
	// It is an error to assign a value with a non-zero fractional
	// part to an integer, or if the assignment would overflow or
	// underflow, or in general if the value cannot be represented
	// by the type of the variable.
	switch a.t {
	case IdealFloatType:
		rat = a.asIdealFloat()()
		if t.isInteger() && !rat.IsInt() {
			a.diag("constant %v truncated to integer", ratToString(rat))
			return nil
		}
	case IdealIntType:
		i := a.asIdealInt()()
		rat = bignum.MakeRat(i, bignum.Nat(1))
	default:
		log.Crashf("unexpected ideal type %v", a.t)
	}

	// Check bounds
	if t, ok := t.lit().(BoundedType); ok {
		if rat.Cmp(t.minVal()) < 0 {
			a.diag("constant %v underflows %v", ratToString(rat), t)
			return nil
		}
		if rat.Cmp(t.maxVal()) > 0 {
			a.diag("constant %v overflows %v", ratToString(rat), t)
			return nil
		}
	}

	// Convert rat to type t.
	res := a.newExpr(t, a.desc)
	switch t := t.lit().(type) {
	case *uintType:
		n, d := rat.Value()
		f := n.Quo(bignum.MakeInt(false, d))
		v := f.Abs().Value()
		res.eval = func(*Thread) uint64 { return v }
	case *intType:
		n, d := rat.Value()
		f := n.Quo(bignum.MakeInt(false, d))
		v := f.Value()
		res.eval = func(*Thread) int64 { return v }
	case *idealIntType:
		n, d := rat.Value()
		f := n.Quo(bignum.MakeInt(false, d))
		res.eval = func() *bignum.Integer { return f }
	case *floatType:
		n, d := rat.Value()
		v := float64(n.Value()) / float64(d.Value())
		res.eval = func(*Thread) float64 { return v }
	case *idealFloatType:
		res.eval = func() *bignum.Rational { return rat }
	default:
		log.Crashf("cannot convert to type %T", t)
	}

	return res
}