Skip to content

Commit

Permalink
Fix division to use bigint and fix some other tests that broke with p…
Browse files Browse the repository at this point in the history
…roper negative handling
  • Loading branch information
mkorbel1 committed Sep 18, 2023
1 parent d25abe2 commit c8b79ef
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 27 deletions.
28 changes: 16 additions & 12 deletions lib/src/values/logic_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -895,12 +895,14 @@ abstract class LogicValue implements Comparable<LogicValue> {
/// Division operation.
///
// ignore: avoid_dynamic_calls
LogicValue operator /(dynamic other) => _doMath(other, (a, b) => a ~/ b);
LogicValue operator /(dynamic other) =>
_doMath(other, (a, b) => a ~/ b, isDivision: true);

/// Modulo operation.
///
// ignore: avoid_dynamic_calls
LogicValue operator %(dynamic other) => _doMath(other, (a, b) => a % b);
LogicValue operator %(dynamic other) =>
_doMath(other, (a, b) => a % b, isDivision: true);

/// Ceil of log base 2 operation.
///
Expand Down Expand Up @@ -944,7 +946,12 @@ abstract class LogicValue implements Comparable<LogicValue> {
///
/// Handles width and bounds checks as well as proper conversion between
/// different types of representation.
LogicValue _doMath(dynamic other, dynamic Function(dynamic a, dynamic b) op) {
///
/// If the math [isDivision], then 64-bit ([_INT_BITS]) operations have some
/// special consideration for two's complement math, so it will use an
/// unsigned [BigInt] for math.
LogicValue _doMath(dynamic other, dynamic Function(dynamic a, dynamic b) op,
{bool isDivision = false}) {
if (!(other is int || other is LogicValue || other is BigInt)) {
throw UnsupportedTypeException(other, [int, LogicValue, BigInt]);
}
Expand All @@ -961,16 +968,16 @@ abstract class LogicValue implements Comparable<LogicValue> {
return LogicValue.filled(other.width, LogicValue.x);
}

if (width > _INT_BITS || (other is LogicValue && other.width > _INT_BITS)) {
final widthComparison = isDivision ? _INT_BITS - 1 : _INT_BITS;

if (width > widthComparison ||
(other is LogicValue && other.width > widthComparison)) {
final a = toBigInt();
final b = other is BigInt
? other
: other is int
? BigInt.from(other).toUnsigned(_INT_BITS)
: other is LogicValue
? other.toBigInt()
: throw Exception(
'Unexpected big type: ${other.runtimeType}.');
: (other as LogicValue).toBigInt();
return LogicValue.ofBigInt(op(a, b) as BigInt, width);
} else {
final a = toInt();
Expand Down Expand Up @@ -1078,10 +1085,7 @@ abstract class LogicValue implements Comparable<LogicValue> {
? other
: other is int
? BigInt.from(other).toUnsigned(_INT_BITS)
: other is LogicValue
? other.toBigInt()
: throw Exception(
'Unexpected big type: ${other.runtimeType}.');
: (other as LogicValue).toBigInt();
} else {
if (width < _INT_BITS) {
a = toInt();
Expand Down
31 changes: 16 additions & 15 deletions test/logic_value_width_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ void main() {
LogicValue.ofInt(0, 128));
});

test('mod3 sizes', () {
expect((LogicValue.ofInt(-5, 64) % 3).toInt(),
(LogicValue.ofInt(-5, 80) % 3).toInt());
});

group('values test', () {
for (final len in [63, 64, 65, 66, 67]) {
final sslv = LogicValue.ofInt(4, len); // small Int hold Big
Expand Down Expand Up @@ -88,24 +93,20 @@ void main() {
expect(fblv > bblv, LogicValue.one);
});

test('big math len=$len', () {
expect(sslv + fslv, LogicValue.ofInt(2, len));
expect(sslv - fslv, LogicValue.ofInt(6, len));
expect(fslv - sslv, LogicValue.ofInt(-6, len));

expect(sslv * fslv, LogicValue.ofInt(-8, len));

expect(sslv + fslv, LogicValue.ofBigInt(BigInt.from(2), len));
expect(sslv - fslv, LogicValue.ofBigInt(BigInt.from(6), len));
expect(fslv - sslv, LogicValue.ofBigInt(BigInt.from(-6), len));

expect(fslv * sslv, LogicValue.ofBigInt(BigInt.from(-8), len));
test('cross compare len=$len', () {
if (len <= 64) {
expect(bslv.eq(bblv), LogicValue.one);
} else {
expect(bslv < bblv, LogicValue.one);
}
});

test('big math len=$len', () {
expect(sblv + fblv, LogicValue.ofInt(2, len));
expect(sblv - fblv, LogicValue.ofInt(6, len));
expect(fblv - sblv, LogicValue.ofInt(-6, len));
expect(fblv - sblv, LogicValue.ofBigInt(BigInt.from(-6), len));

expect(sblv * fblv, LogicValue.ofInt(-8, len));
expect(sblv * fblv, LogicValue.ofBigInt(BigInt.from(-8), len));

expect(sblv + fblv, LogicValue.ofBigInt(BigInt.from(2), len));
expect(sblv - fblv, LogicValue.ofBigInt(BigInt.from(6), len));
Expand All @@ -131,7 +132,7 @@ void main() {
});

test('clog test len=$len', () {
final negnum = LogicValue.ofInt(-1, len);
final negnum = LogicValue.ofBigInt(-BigInt.one, len);
expect(negnum.clog2(), LogicValue.ofInt(len, len));
for (final l in [1, 2, 3]) {
expect((negnum >>> l).clog2(), LogicValue.ofInt(len - l, len));
Expand Down

0 comments on commit c8b79ef

Please sign in to comment.