Skip to content

Instantly share code, notes, and snippets.

@ip
Created September 1, 2018 05:42
Show Gist options
  • Select an option

  • Save ip/cf39979441efc9f1481bde105b5220a2 to your computer and use it in GitHub Desktop.

Select an option

Save ip/cf39979441efc9f1481bde105b5220a2 to your computer and use it in GitHub Desktop.
using System;
public class PositiveOverflowException : Exception {}
public class NegativeOverflowException : Exception {}
// TODO:
// - increment
// - left shift
public static class BitwiseArithmetics {
private const int bitsNum = sizeof(int) * 8;
public static int Sum(int a, int b) {
int result = 0;
bool carry = false;
for (int i = 0; i != bitsNum; i++) {
bool a_i = _GetBit(a, i);
bool b_i = _GetBit(b, i);
BitSumResult sum = _SumBits(a_i, b_i, carry);
carry = sum.overflow;
result = _SetBit(result, i, sum.result);
bool isLastBit = i == bitsNum - 1;
if (isLastBit) {
_HandleOverflow(a_i, b_i, sum.result);
}
}
return result;
}
private struct BitSumResult {
public bool result, overflow;
}
private static BitSumResult _SumBits(bool a, bool b, bool carry) {
bool overflow, result;
if (carry) {
if (a && b) { overflow = true; result = true; }
if (a || b) { overflow = true; result = false; }
else { overflow = false; result = true; }
} else {
if (a && b) { overflow = true; result = false; }
if (a || b) { overflow = false; result = true; }
else { overflow = false; result = false; }
}
return new BitSumResult { overflow = overflow, result = result };
}
private static bool _GetBit(int num, int index) {
int mask = 1 << index;
return (num & mask) != 0;
}
private static int _SetBit(int num, int index, bool value) {
int positionMask = 1 << index;
int clearMask = ~positionMask;
int valueMask = value ? positionMask : 0;
return (num & clearMask) | valueMask;
}
private static void _HandleOverflow(bool aSign, bool bSign, bool resultSign) {
bool sourceSignsMatch = !(aSign ^ bSign);
bool signChanged = aSign ^ resultSign;
bool isOverflow = sourceSignsMatch && signChanged;
if (isOverflow) {
if (resultSign) {
throw new PositiveOverflowException();
} else {
throw new NegativeOverflowException();
}
}
}
}
using System;
using NUnit.Framework;
[TestFixture]
public class BitwiseArithmeticsTest {
[Test]
public void SumsTwoPositives() {
_TestPair(52985, 1293953);
}
[Test]
public void SumsPositiveAndNegative() {
_TestPair(92813, -2133);
}
[Test]
public void SumsMinusOneAndOne() {
_TestPair(-1, 1);
}
[Test]
public void SumsTwoNegatives() {
_TestPair(-81324897, -98234);
}
[Test]
public void SumsPositiveAndZero() {
_TestPair(1234, 0);
}
[Test]
public void HandlesPositiveOverflow() {
Assert.Throws<PositiveOverflowException>(() => {
BitwiseArithmetics.Sum(Int32.MaxValue, 1);
});
}
[Test]
public void HandlesNegativeOverflow() {
Assert.Throws<NegativeOverflowException>(() => {
BitwiseArithmetics.Sum(Int32.MinValue, -1);
});
}
private void _TestPair(int a, int b) {
int expected = a + b;
int actual = BitwiseArithmetics.Sum(a, b);
Assert.AreEqual(expected, actual);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment