-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide a way to perform Add with carry and Subtract with borrow #48247
Comments
Tagging subscribers to this area: @tannergooding, @pgovind Issue DetailsBackground and Motivation
Proposed API |
This likely needs more design work and usage samples. |
@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 |
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:
|
C/C++ exposes it as Proposed APInamespace System
{
partial class Math
{
public static (uint Sum, bool Carry) AddWithCarry(uint a, uint b, bool carry);
public static (nuint Sum, bool Carry) AddWithCarry(nuint a, nuint b, bool carry);
public static (ulong Sum, bool Carry) AddWithCarry(ulong a, ulong b, bool carry);
}
} Usage ExamplesIn // Highest 32 bits is non-zero. Calculate 5 more partial products.
-tmp2 = UInt32x32To64(d1.Low, d2.High);
-tmp += tmp2; // this could generate carry
+(tmp, bool carry) = Math.AddWithCarry(tmp, UInt32x32To64(d1.Low, d2.High), false);
-uint tmp3 = 0;
-if (tmp < tmp2) // detect carry
- tmp3 = 1;
+uint tmp3 = Convert.ToUInt32(carry);
-tmp2 = UInt32x32To64(d1.High, d2.Low);
-tmp += tmp2; // this could generate carry
+(tmp, carry) = Math.AddWithCarry(tmp, UInt32x32To64(d1.High, d2.Low), false);
bufProd.U2 = (uint)tmp;
-if (tmp < tmp2) // detect carry
- tmp3++;
+(tmp3, _) = Math.AddWithCarry(tmp3, 0, carry);
-tmp2 = ((ulong)tmp3 << 32) | (tmp >> 32);
-tmp = UInt32x32To64(d1.Mid, d2.High);
-tmp += tmp2; // this could generate carry
+(tmp, carry) = Math.AddWithCarry(((ulong)tmp3 << 32) | (tmp >> 32), UInt32x32To64(d1.Mid, d2.High), false);
-tmp3 = 0;
-if (tmp < tmp2) // detect carry
- tmp3 = 1;
+tmp3 = Convert.ToUInt32(carry);
-tmp2 = UInt32x32To64(d1.High, d2.Mid);
-tmp += tmp2; // this could generate carry
+(tmp, carry) = Math.AddWithCarry(tmp, UInt32x32To64(d1.High, d2.Mid), false);
bufProd.U3 = (uint)tmp;
-if (tmp < tmp2) // detect carry
- tmp3++;
+(tmp3, _) = Math.AddWithCarry(tmp3, 0, carry);
tmp = ((ulong)tmp3 << 32) | (tmp >> 32);
bufProd.High64 = UInt32x32To64(d1.High, d2.High) + tmp;
hiProd = 5; In uint[] bits = new uint[left.Length + 1];
-long digit = (long)left[0] + right;
-bits[0] = unchecked((uint)digit);
-long carry = digit >> 32;
+(bits[0], bool carry) = Math.AddWithCarry(left[0], right, false);
for (int i = 1; i < left.Length; i++)
{
- digit = left[i] + carry;
- bits[i] = unchecked((uint)digit);
- carry = digit >> 32;
+ (bits[i], carry) = Math.AddWithCarry(left[i], 0, carry);
}
-bits[left.Length] = (uint)carry;
+bits[left.Length] = Convert.ToUInt32(carry);
return bits; |
Background and Motivation
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 forBitInteger
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 likeruntime/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigIntegerCalculator.AddSub.cs
Lines 75 to 79 in 21a03c3
Risks
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
.The text was updated successfully, but these errors were encountered: