You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Provide a way to perform Add with carry and Subtract with borrow #48247
The motivation behind this proposal is to provide API that can be useful for adding/subtracting big integers without the need of calculating carry manually. Currently, the only way that I'm aware of .NET uses ADC assembly instruction is an overflow check, followed by a conditional jump to the exception throw. With a proper intrinsics/Math method it could be leveraged to provide a fast add with carry operation. This would be beneficial for BitInteger but also for any other code using this API.
Proposed API
namespace System
{
public static partial class Math
{
+ ulong AddWithCarry(ulong a, ulong b, ref ulong carry);
}
}
Usage Examples
The immediate beneficent would be BigInteger with methods like
The implementation overhead. This would require to go to JIT/intrinsics area and provide a proper fallback, something similar to what was done in Math.BigMul.
Reacted by GSPP, Pent Ploompuu, Abel Braaksma, ちーず(・8・)けーき, Daniel Svensson, Fabien Barbier, Linus Schwartz Hamlin and David Jürgens
@tannergooding Could you clarify whether it's an issue author responsibility, meaning: me, or is it a request for various people to chime in? If the first, I'm not sure if I can provide more. The finding is based on my work in https://github.com/NethermindEth/int256 and my search in the BigInteger area to find how it's done in there. In both cases ADC looked like a good match for carrying over.
Its ultimately the area owners (my own and Prashanth's) responsibility to drive this if we feel its worth getting in.
However, interested community members are also free to help out here and to drive much of the design work/addressing feedback/etc. This can sometimes be faster based on what workload we otherwise have.
In the case of this API, I do believe its worth adding and there are corresponding proposals such as #54439 or #46259 that are in a similar vein.
As far as this proposal goes, I think the "design" work that is needed includes:
Showing what other languages are doing (C/C++, Rust, Java, Go, Swift, etc)
e.g. C/C++ expose what is effectively bool addcarry(bool carry, uint a, uint b, out uint result)
This will help ensure we are exposing the right shape
Showing what logic this replaces today
e.g. Today you manually track the carry by doing a twice as large addition or comparing the result to the inputs
This is displayed, should be broadened a bit to include the carry declaration and ideally to show the replacement code using this API instead
Sharing how this would impact performance in given workloads
IIRC, the simple single case is typically the same, but multiple unrolled adds can be much better
C/C++ exposes it as unsigned char _addcarry_u64(unsigned char, unsigned __int64, unsigned __int64, unsigned __int64 *), but compilers recognize some of the comparison based code patterns also.
Rust exposes it as pub unsafe fn _addcarry_u64(c_in: u8, a: u64, b: u64, out: &mut u64) -> u8
Go exposes it as func Add64(x, y, carry uint64) (sum, carryOut uint64)
Activity
tannergooding commentedon Jun 17, 2021
This likely needs more design work and usage samples.
Scooletz commentedon Jun 21, 2021
@tannergooding Could you clarify whether it's an issue author responsibility, meaning: me, or is it a request for various people to chime in? If the first, I'm not sure if I can provide more. The finding is based on my work in https://github.com/NethermindEth/int256 and my search in the
BigIntegerarea to find how it's done in there. In both casesADClooked like a good match for carrying over.tannergooding commentedon Jun 21, 2021
Its ultimately the area owners (my own and Prashanth's) responsibility to drive this if we feel its worth getting in.
However, interested community members are also free to help out here and to drive much of the design work/addressing feedback/etc. This can sometimes be faster based on what workload we otherwise have.
In the case of this API, I do believe its worth adding and there are corresponding proposals such as #54439 or #46259 that are in a similar vein.
As far as this proposal goes, I think the "design" work that is needed includes:
bool addcarry(bool carry, uint a, uint b, out uint result)pentp commentedon Sep 6, 2021
C/C++ exposes it as
unsigned char _addcarry_u64(unsigned char, unsigned __int64, unsigned __int64, unsigned __int64 *), but compilers recognize some of the comparison based code patterns also.Rust exposes it as
pub unsafe fn _addcarry_u64(c_in: u8, a: u64, b: u64, out: &mut u64) -> u8Go exposes it as
func Add64(x, y, carry uint64) (sum, carryOut uint64)Proposed API
Usage Examples
In
decimal.DecCalc.VarDecMulthis would be used quite a lot:In
BigIntegerCalculator.Add(uint[] left, uint right):scottmcm commentedon Nov 20, 2025
Rust now exposes this in a platform-independent way (not just via
archintrinsics) throughu64::carrying_mul_addand friends.