Closed
Description
This is a proposal for a (backward-compatible) language extension. The notion of comma-ok expressions can be extended in a natural way to the 4 basic arithmetic operations (+, -, *, /) such that a 2nd result value (traditionally the "ok" value) provides the carry, borrow, overflow, and remainder value, respectively. Specifically (spec wording): ----- A binary expression with one the four basic arithmetic operators may be used in an assignment of initialization of the special form: z, c = x op y z, c := x op y var z, c = x op y var z, c T = x op y The operator op must be one of +, -, *, or /. The value and type of z is the same as in the single-result form. In the special form, the type of c is the same as the type of z, and the value of c is defined as follows: For +, -, and /, the value of c is (x op y) >> s with the operation carried out in twice the precision of the types of the operands, and with s = operand type size in bits. For /, the value of c is the remainder x%y. In other words: for +, c is the "carry" value (0 or 1) for -, c is the "borrow" value (0 or -1) for *, c is the "overflow" value for /, c is the remainder ----- The implementation is straight-forward since these c values tend to be computed anyway: For +, and -, the value of c corresponds to the "carry/borrow bit" usually computed always for these operations. The carry bit simply needs to be converted and stored (between 1 to 3 machine instructions, depending on architecture, storage location). Division operations usually leave the remainder in a register. Only multiplication requires double-width arithmetic, and only if c is required. Applications: - Code that needs to check for integer overflow can be simplified. For unsigned ints, the c value is the desired bit. - Numeric conversions (from integer to decimal) require both / and % on the same operands. Providing q, r := x/y is likely to run twice as fast w/o the need for the compiler to detect that a % operation following a / is using the same operands. - Some of the core routines required for arbitrary precision arithmetic can be written in a straight-forward manner in Go and should achieve similar performance as corresponding assembly code, without the need for fancy compiler optimizations. Concrete example: If x, y, z represent fixed-size high precision unsigned integers (n*64 bits), + could be written as follows: const n = 100 var x, y, z [n]uint64 // compute z = x + y var c uint64 for i, x := range x { z[i], c = x + y[i] + c } Without the special z, c = x + y form, analogous code written in c will be prohibitively expensive compared to the respective assembly.