Skip to content

proposal: spec: extend comma-ok expressions to + - * / arithmetic #6815

@griesemer

Description

@griesemer
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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions