func (t *intType) maxVal() *bignum.Rational { bits := t.Bits if bits == 0 { bits = uint(8 * unsafe.Sizeof(int(0))) } return bignum.MakeRat(bignum.Int(1).Shl(bits-1).Add(bignum.Int(-1)), bignum.Nat(1)) }
func (t *uintType) maxVal() *bignum.Rational { bits := t.Bits if bits == 0 { if t.Ptr { bits = uint(8 * unsafe.Sizeof(uintptr(0))) } else { bits = uint(8 * unsafe.Sizeof(uint(0))) } } return bignum.MakeRat(bignum.Int(1).Shl(bits).Add(bignum.Int(-1)), bignum.Nat(1)) }
func main() { sum := 0 two_1000 := bignum.Int(2) for i := 1; i < 1000; i++ { two_1000 = two_1000.Mul(bignum.Int(2)) } for _, v := range two_1000.String() { c, _ := strconv.Atoi(string(v)) sum += c } fmt.Printf("%d\n", sum) }
func main() { a := bignum.Int(1) b := bignum.Int(1) i := 2 for { a, b = b, a.Add(b) i += 1 if len(b.String()) == 1000 { break } } fmt.Printf("%d\n", i) }
// convertToInt converts this expression to an integer, if possible, // or produces an error if not. This accepts ideal ints, uints, and // ints. If max is not -1, produces an error if possible if the value // exceeds max. If negErr is not "", produces an error if possible if // the value is negative. func (a *expr) convertToInt(max int64, negErr string, errOp string) *expr { switch a.t.lit().(type) { case *idealIntType: val := a.asIdealInt()() if negErr != "" && val.IsNeg() { a.diag("negative %s: %s", negErr, val) return nil } bound := max if negErr == "slice" { bound++ } if max != -1 && val.Cmp(bignum.Int(bound)) >= 0 { a.diag("index %s exceeds length %d", val, max) return nil } return a.convertTo(IntType) case *uintType: // Convert to int na := a.newExpr(IntType, a.desc) af := a.asUint() na.eval = func(t *Thread) int64 { return int64(af(t)) } return na case *intType: // Good as is return a } a.diag("illegal operand type for %s\n\t%v", errOp, a.t) return nil }
func (a *stmtCompiler) compileIncDecStmt(s *ast.IncDecStmt) { // Create temporary block for extractEffect bc := a.enterChild() defer bc.exit() l := a.compileExpr(bc.block, false, s.X) if l == nil { return } if l.evalAddr == nil { l.diag("cannot assign to %s", l.desc) return } if !(l.t.isInteger() || l.t.isFloat()) { l.diagOpType(s.Tok, l.t) return } var op token.Token var desc string switch s.Tok { case token.INC: op = token.ADD desc = "increment statement" case token.DEC: op = token.SUB desc = "decrement statement" default: log.Crashf("Unexpected IncDec token %v", s.Tok) } effect, l := l.extractEffect(bc.block, desc) one := l.newExpr(IdealIntType, "constant") one.pos = s.Pos() one.eval = func() *bignum.Integer { return bignum.Int(1) } binop := l.compileBinaryExpr(op, l, one) if binop == nil { return } assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "", "") if assign == nil { log.Crashf("compileAssign type check failed") } lf := l.evalAddr a.push(func(v *Thread) { effect(v) assign(lf(v), v) }) }
func (a *exprInfo) compileCharLit(lit string) *expr { if lit[0] != '\'' { // Caught by parser a.silentErrors++ return nil } v, _, tail, err := strconv.UnquoteChar(lit[1:], '\'') if err != nil || tail != "'" { // Caught by parser a.silentErrors++ return nil } return a.compileIdealInt(bignum.Int(int64(v)), "character literal") }
func (a *expr) genUnaryOpXor(v *expr) { switch a.t.lit().(type) { case *uintType: vf := v.asUint() a.eval = func(t *Thread) uint64 { v := vf(t); return ^v } case *intType: vf := v.asInt() a.eval = func(t *Thread) int64 { v := vf(t); return ^v } case *idealIntType: v := v.asIdealInt()() val := v.Neg().Sub(bignum.Int(1)) a.eval = func() *bignum.Integer { return val } default: log.Crashf("unexpected type %v at %v", a.t, a.pos) } }
func Mul(a, b string) string { ra, rb, f := twop(a, b) ar := bignum.Rat(ra, int64(f)) br := bignum.Rat(rb, int64(f)) i, n := ar.Mul(br).Value() nv := n.Value() d := uint64(1) for d%nv != 0 { d *= 10 } i = i.Mul1(int64(d / nv)) if uint64(f) < d { i = i.Div(bignum.Int(int64(d / uint64(f)))) d = uint64(f) } return String(i.Value(), int(d)) }
func newTestWorld() *World { w := NewWorld() def := func(name string, t Type, val interface{}) { w.DefineVar(name, t, toValue(val)) } w.DefineConst("c", IdealIntType, toValue(bignum.Int(1))) def("i", IntType, 1) def("i2", IntType, 2) def("u", UintType, uint(1)) def("f", FloatType, 1.0) def("s", StringType, "abc") def("t", NewStructType([]StructField{StructField{"a", IntType, false}}), vstruct{1}) def("ai", NewArrayType(2, IntType), varray{1, 2}) def("aai", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{1, 2}, varray{3, 4}}) def("aai2", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{5, 6}, varray{7, 8}}) def("fn", NewFuncType([]Type{IntType}, false, []Type{IntType}), &testFunc{}) def("oneTwo", NewFuncType([]Type{}, false, []Type{IntType, IntType}), &oneTwoFunc{}) def("void", NewFuncType([]Type{}, false, []Type{}), &voidFunc{}) def("sli", NewSliceType(IntType), vslice{varray{1, 2, 3}, 2, 3}) return w }
func (t *idealIntType) Zero() Value { return &idealIntV{bignum.Int(0)} }
func (t *floatType) Zero() Value { switch t.Bits { case 32: res := float32V(0) return &res case 64: res := float64V(0) return &res case 0: res := floatV(0) return &res } panic("unexpected float bit count") } var maxFloat32Val = bignum.MakeRat(bignum.Int(0xffffff).Shl(127-23), bignum.Nat(1)) var maxFloat64Val = bignum.MakeRat(bignum.Int(0x1fffffffffffff).Shl(1023-52), bignum.Nat(1)) var minFloat32Val = maxFloat32Val.Neg() var minFloat64Val = maxFloat64Val.Neg() func (t *floatType) minVal() *bignum.Rational { bits := t.Bits if bits == 0 { bits = uint(8 * unsafe.Sizeof(float(0))) } switch bits { case 32: return minFloat32Val case 64: return minFloat64Val }
func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr { // Save the original types of l.t and r.t for error messages. origlt := l.t origrt := r.t // XXX(Spec) What is the exact definition of a "named type"? // XXX(Spec) Arithmetic operators: "Integer types" apparently // means all types compatible with basic integer types, though // this is never explained. Likewise for float types, etc. // This relates to the missing explanation of named types. // XXX(Spec) Operators: "If both operands are ideal numbers, // the conversion is to ideal floats if one of the operands is // an ideal float (relevant for / and %)." How is that // relevant only for / and %? If I add an ideal int and an // ideal float, I get an ideal float. if op != token.SHL && op != token.SHR { // Except in shift expressions, if one operand has // numeric type and the other operand is an ideal // number, the ideal number is converted to match the // type of the other operand. if (l.t.isInteger() || l.t.isFloat()) && !l.t.isIdeal() && r.t.isIdeal() { r = r.convertTo(l.t) } else if (r.t.isInteger() || r.t.isFloat()) && !r.t.isIdeal() && l.t.isIdeal() { l = l.convertTo(r.t) } if l == nil || r == nil { return nil } // Except in shift expressions, if both operands are // ideal numbers and one is an ideal float, the other // is converted to ideal float. if l.t.isIdeal() && r.t.isIdeal() { if l.t.isInteger() && r.t.isFloat() { l = l.convertTo(r.t) } else if l.t.isFloat() && r.t.isInteger() { r = r.convertTo(l.t) } if l == nil || r == nil { return nil } } } // Useful type predicates // TODO(austin) CL 33668 mandates identical types except for comparisons. compat := func() bool { return l.t.compat(r.t, false) } integers := func() bool { return l.t.isInteger() && r.t.isInteger() } floats := func() bool { return l.t.isFloat() && r.t.isFloat() } strings := func() bool { // TODO(austin) Deal with named types return l.t == StringType && r.t == StringType } booleans := func() bool { return l.t.isBoolean() && r.t.isBoolean() } // Type check var t Type switch op { case token.ADD: if !compat() || (!integers() && !floats() && !strings()) { a.diagOpTypes(op, origlt, origrt) return nil } t = l.t case token.SUB, token.MUL, token.QUO: if !compat() || (!integers() && !floats()) { a.diagOpTypes(op, origlt, origrt) return nil } t = l.t case token.REM, token.AND, token.OR, token.XOR, token.AND_NOT: if !compat() || !integers() { a.diagOpTypes(op, origlt, origrt) return nil } t = l.t case token.SHL, token.SHR: // XXX(Spec) Is it okay for the right operand to be an // ideal float with no fractional part? "The right // operand in a shift operation must be always be of // unsigned integer type or an ideal number that can // be safely converted into an unsigned integer type // (§Arithmetic operators)" suggests so and 6g agrees. if !l.t.isInteger() || !(r.t.isInteger() || r.t.isIdeal()) { a.diagOpTypes(op, origlt, origrt) return nil } // The right operand in a shift operation must be // always be of unsigned integer type or an ideal // number that can be safely converted into an // unsigned integer type. if r.t.isIdeal() { r2 := r.convertTo(UintType) if r2 == nil { return nil } // If the left operand is not ideal, convert // the right to not ideal. if !l.t.isIdeal() { r = r2 } // If both are ideal, but the right side isn't // an ideal int, convert it to simplify things. if l.t.isIdeal() && !r.t.isInteger() { r = r.convertTo(IdealIntType) if r == nil { log.Crashf("conversion to uintType succeeded, but conversion to idealIntType failed") } } } else if _, ok := r.t.lit().(*uintType); !ok { a.diag("right operand of shift must be unsigned") return nil } if l.t.isIdeal() && !r.t.isIdeal() { // XXX(Spec) What is the meaning of "ideal >> // non-ideal"? Russ says the ideal should be // converted to an int. 6g propagates the // type down from assignments as a hint. l = l.convertTo(IntType) if l == nil { return nil } } // At this point, we should have one of three cases: // 1) uint SHIFT uint // 2) int SHIFT uint // 3) ideal int SHIFT ideal int t = l.t case token.LOR, token.LAND: if !booleans() { return nil } // XXX(Spec) There's no mention of *which* boolean // type the logical operators return. From poking at // 6g, it appears to be the named boolean type, NOT // the type of the left operand, and NOT an unnamed // boolean type. t = BoolType case token.ARROW: // The operands in channel sends differ in type: one // is always a channel and the other is a variable or // value of the channel's element type. log.Crash("Binary op <- not implemented") t = BoolType case token.LSS, token.GTR, token.LEQ, token.GEQ: // XXX(Spec) It's really unclear what types which // comparison operators apply to. I feel like the // text is trying to paint a Venn diagram for me, // which it's really pretty simple: <, <=, >, >= apply // only to numeric types and strings. == and != apply // to everything except arrays and structs, and there // are some restrictions on when it applies to slices. if !compat() || (!integers() && !floats() && !strings()) { a.diagOpTypes(op, origlt, origrt) return nil } t = BoolType case token.EQL, token.NEQ: // XXX(Spec) The rules for type checking comparison // operators are spread across three places that all // partially overlap with each other: the Comparison // Compatibility section, the Operators section, and // the Comparison Operators section. The Operators // section should just say that operators require // identical types (as it does currently) except that // there a few special cases for comparison, which are // described in section X. Currently it includes just // one of the four special cases. The Comparison // Compatibility section and the Comparison Operators // section should either be merged, or at least the // Comparison Compatibility section should be // exclusively about type checking and the Comparison // Operators section should be exclusively about // semantics. // XXX(Spec) Comparison operators: "All comparison // operators apply to basic types except bools." This // is very difficult to parse. It's explained much // better in the Comparison Compatibility section. // XXX(Spec) Comparison compatibility: "Function // values are equal if they refer to the same // function." is rather vague. It should probably be // similar to the way the rule for map values is // written: Function values are equal if they were // created by the same execution of a function literal // or refer to the same function declaration. This is // *almost* but not quite waht 6g implements. If a // function literals does not capture any variables, // then multiple executions of it will result in the // same closure. Russ says he'll change that. // TODO(austin) Deal with remaining special cases if !compat() { a.diagOpTypes(op, origlt, origrt) return nil } // Arrays and structs may not be compared to anything. switch l.t.(type) { case *ArrayType, *StructType: a.diagOpTypes(op, origlt, origrt) return nil } t = BoolType default: log.Crashf("unknown binary operator %v", op) } desc, ok := binOpDescs[op] if !ok { desc = op.String() + " expression" binOpDescs[op] = desc } // Check for ideal divide by zero switch op { case token.QUO, token.REM: if r.t.isIdeal() { if (r.t.isInteger() && r.asIdealInt()().IsZero()) || (r.t.isFloat() && r.asIdealFloat()().IsZero()) { a.diag("divide by zero") return nil } } } // Compile expr := a.newExpr(t, desc) switch op { case token.ADD: expr.genBinOpAdd(l, r) case token.SUB: expr.genBinOpSub(l, r) case token.MUL: expr.genBinOpMul(l, r) case token.QUO: expr.genBinOpQuo(l, r) case token.REM: expr.genBinOpRem(l, r) case token.AND: expr.genBinOpAnd(l, r) case token.OR: expr.genBinOpOr(l, r) case token.XOR: expr.genBinOpXor(l, r) case token.AND_NOT: expr.genBinOpAndNot(l, r) case token.SHL: if l.t.isIdeal() { lv := l.asIdealInt()() rv := r.asIdealInt()() const maxShift = 99999 if rv.Cmp(bignum.Int(maxShift)) > 0 { a.diag("left shift by %v; exceeds implementation limit of %v", rv, maxShift) expr.t = nil return nil } val := lv.Shl(uint(rv.Value())) expr.eval = func() *bignum.Integer { return val } } else { expr.genBinOpShl(l, r) } case token.SHR: if l.t.isIdeal() { lv := l.asIdealInt()() rv := r.asIdealInt()() val := lv.Shr(uint(rv.Value())) expr.eval = func() *bignum.Integer { return val } } else { expr.genBinOpShr(l, r) } case token.LSS: expr.genBinOpLss(l, r) case token.GTR: expr.genBinOpGtr(l, r) case token.LEQ: expr.genBinOpLeq(l, r) case token.GEQ: expr.genBinOpGeq(l, r) case token.EQL: expr.genBinOpEql(l, r) case token.NEQ: expr.genBinOpNeq(l, r) case token.LAND: expr.genBinOpLogAnd(l, r) case token.LOR: expr.genBinOpLogOr(l, r) default: log.Crashf("Compilation of binary op %v not implemented", op) } return expr }
) var undefined = "undefined" var typeAsExpr = "type .* used as expression" var badCharLit = "character literal" var illegalEscape = "illegal char escape" var opTypes = "illegal (operand|argument) type|cannot index into" var badAddrOf = "cannot take the address" var constantTruncated = "constant [^ ]* truncated" var constantUnderflows = "constant [^ ]* underflows" var constantOverflows = "constant [^ ]* overflows" var implLimit = "implementation limit" var mustBeUnsigned = "must be unsigned" var divByZero = "divide by zero" var hugeInteger = bignum.Int(1).Shl(64) var exprTests = []test{ Val("i", 1), CErr("zzz", undefined), // TODO(austin) Test variable in constant context //CErr("t", typeAsExpr), Val("'a'", bignum.Int('a')), Val("'\\uffff'", bignum.Int('\uffff')), Val("'\\n'", bignum.Int('\n')), CErr("''+x", badCharLit), // Produces two parse errors //CErr("'''", ""), CErr("'\n'", badCharLit), CErr("'\\z'", illegalEscape),
package main import ( "bignum" "flag" "fmt" ) var n = flag.Int("n", 27, "number of digits") var silent = flag.Bool("s", false, "don't print result") var ( tmp1 *bignum.Integer tmp2 *bignum.Integer numer = bignum.Int(1) accum = bignum.Int(0) denom = bignum.Int(1) ) func extract_digit() int64 { if numer.Cmp(accum) > 0 { return -1 } // Compute (numer * 3 + accum) / denom tmp1 = numer.Shl(1) bignum.Iadd(tmp1, tmp1, numer) bignum.Iadd(tmp1, tmp1, accum) tmp1, tmp2 := tmp1.QuoRem(denom)
package main import ( "bignum"; "flag"; "fmt"; ) var n = flag.Int("n", 27, "number of digits"); var silent = flag.Bool("s", false, "don't print result"); var ( tmp1 *bignum.Integer; tmp2 *bignum.Integer; numer = bignum.Int(1); accum = bignum.Int(0); denom = bignum.Int(1); ) func extract_digit() int64 { if numer.Cmp(accum) > 0 { return -1; } // Compute (numer * 3 + accum) / denom tmp1 = numer.Shl(1); bignum.Iadd(tmp1, tmp1, numer); bignum.Iadd(tmp1, tmp1, accum); tmp1, tmp2 := tmp1.QuoRem(denom);