carbon-language / carbon-lang

Carbon Language's main repository: documents, design, implementation, and related tools. (NOTE: Carbon Language is experimental; see README)
http://docs.carbon-lang.dev/
Other
32.25k stars 1.48k forks source link

Add clamping-support for integer operations. #1977

Open OlaFosheimGrostad opened 2 years ago

OlaFosheimGrostad commented 2 years ago

Clamping (or "saturation") is as useful as modular arithmetics. I think it would be an improvement to C++ if Carbon provided clamping and modular (wrapping) operators using similar mechanisms. Right now the docs specify that Carbon follows C++, but that modular operators will be considered as future work. I think it would be better for correctness if modular operations don't happen by type, but is explicit. In my opinion that covers most use scenarios on modern CPUs registers with large bit-widths.

So there are two ways to approach this:

  1. Let the user mark the entire expression as clamping/modular.
  2. Introduce separate operators for clamping/modular semantics.

Examples for operators:

   a = b (+) c;  // modular, the roundness suggests wrapping
   a = b [+] c;  // clamping, the squareness suggests clamping

Examples for expressions (not the best syntax):

  a = modular (a+b);
  a = clamping (a+b);

Clamping is particularly useful in SIMD operations, so I guess one would need to figure out what SIMD operations would look like to ensure consistency across builtin types.

h3har commented 2 years ago

What don't you like about Rust's approach?

Rust provides explicit wrapping_add etc. functions on ordinary integer types to opt-in to wrapping arithmetic, but also provides a special generic wrapper type Wrapping<T> that overloads the usual operators such as + to implement wrapping operations. The same goes for clamping (saturating) and modular arithmetic, as well as other operations.

I personally like Rust's approach here. I like the ability to encode the default arithmetic behaviour into the type system (if desired) - although you seem to not like this (any reasons why?). This approach has the benefit of keeping the core language simpler - no need to add additional operators or keywords (although you'd probably use compiler intrinsics to actually implement the ops).

OlaFosheimGrostad commented 2 years ago

Rust provides explicit wrapping_add etc. functions on ordinary integer types to opt-in to wrapping arithmetic, but also provides a special generic wrapper type Wrapping<T> that overloads the usual operators such as + to implement wrapping operations. The same goes for clamping (saturating) and modular arithmetic, as well as other operations.

I am not really using Rust, so I will answer in general.

  1. Casting in expressions makes them hard to read which is why I want to see operators. It also makes you think twice before you use modular arithmetics or clamping semantics.
  2. The problem with std::uint32_t is that people will not switch back to regular "monotonic" integer semantics and thus overflow is not caught and you also miss out on optimizations.
  3. In general you seldom want to do modular arithmetics over 2^N, so if you want to have modular arithmetics the parametric type should let you specify something else, like a prime (I think Ada does this).
  4. Very few calculations will be correct if you drop in a modular/clamping type in a generic function assuming regular integer-semantics, so it is not a good idea to encourage the view that they are interchangeable.
  5. If you have them as operators then libraries can provide the typed versions as user defined types. So having them as operators is more general.
  6. Scalar operators ought be consistent with SIMD.
  7. Usually one does not want to clamp every operator-result in an expression.
github-actions[bot] commented 1 year ago

We triage inactive PRs and issues in order to make it easier to find active work. If this issue should remain active or becomes active again, please comment or remove the inactive label. The long term label can also be added for issues which are expected to take time. This issue is labeled inactive because the last activity was over 90 days ago.