Skip to content

Commit

Permalink
feat(mixed_num): 🔥 drop support for negative values
Browse files Browse the repository at this point in the history
Signed-off-by: Albert Mañosa <26429103+albertms10@users.noreply.github.com>
  • Loading branch information
albertms10 committed May 13, 2024
1 parent fa4286c commit e11f99f
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 12 deletions.
20 changes: 13 additions & 7 deletions lib/src/utils/mixed_num.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:meta/meta.dart' show immutable;
import 'package:music_notes/utils.dart';

/// A mixed number representation.
@immutable
Expand All @@ -16,6 +15,10 @@ final class MixedNum implements Comparable<MixedNum> {
/// Creates a new [MixedNum] from [integer], [numerator], and [denominator].
const MixedNum(this.integer, [this.numerator = 0, this.denominator = 1])
: assert(
integer >= 0,
'The whole part must be greater or equal than zero.',
),
assert(
numerator >= 0,
'The denominator must be greater or equal than zero.',
),
Expand Down Expand Up @@ -47,6 +50,9 @@ final class MixedNum implements Comparable<MixedNum> {

/// Creates a new [MixedNum] from [number] and [tolerance].
factory MixedNum.fromDouble(double number, {int tolerance = 100}) {
assert(!number.isNegative, 'Number must be positive.');
assert(!tolerance.isNegative, 'Tolerance must be positive.');

final wholePart = number.floor();
final fracPart = number - wholePart;

Expand All @@ -56,13 +62,13 @@ final class MixedNum implements Comparable<MixedNum> {
var bestDenominator = 1;
var bestError = double.infinity;

for (var den = 1; den <= tolerance; ++den) {
final num = (fracPart * den).round();
final error = (fracPart - num / den).abs();
for (var denominator = 1; denominator <= tolerance; ++denominator) {
final numerator = (fracPart * denominator).round();
final error = (fracPart - numerator / denominator).abs();
if (error < bestError) {
bestError = error;
bestNumerator = num;
bestDenominator = den;
bestNumerator = numerator;
bestDenominator = denominator;
gcdValue = bestNumerator.gcd(bestDenominator);
}
if (error == 0) break;
Expand All @@ -82,7 +88,7 @@ final class MixedNum implements Comparable<MixedNum> {
MixedNum get simple => MixedNum.fromDouble(toDouble());

/// This [MixedNum] as a [double].
double toDouble() => integer + _fractionPart * integer.nonZeroSign;
double toDouble() => integer + _fractionPart;

double get _fractionPart => numerator / denominator;

Expand Down
14 changes: 9 additions & 5 deletions test/utils/mixed_num_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ void main() {
test('throws an assertion error when arguments are incorrect', () {
expect(() => MixedNum(1, -2), throwsA(isA<AssertionError>()));
expect(() => MixedNum(1, 1, 0), throwsA(isA<AssertionError>()));
expect(() => MixedNum(-1), throwsA(isA<AssertionError>()));
});
});

Expand All @@ -29,7 +30,6 @@ void main() {
expect(MixedNum.parse('5 3/5'), const MixedNum(5, 3, 5));
expect(MixedNum.parse('4 5/4'), const MixedNum(4, 5, 4));
expect(MixedNum.parse('32 10/111'), const MixedNum(32, 10, 111));
expect(MixedNum.parse('-4 3/4'), const MixedNum(-4, 3, 4));
});
});

Expand All @@ -47,14 +47,21 @@ void main() {
);
expect(MixedNum.fromDouble(1.375), const MixedNum(1, 3, 8));
});

test('throws an assertion error when arguments are incorrect', () {
expect(() => MixedNum.fromDouble(-1), throwsA(isA<AssertionError>()));
expect(
() => MixedNum.fromDouble(1, tolerance: -1),
throwsA(isA<AssertionError>()),
);
});
});

group('.simple', () {
test('returns the simplified version of this MixedNum', () {
expect(const MixedNum(0, 1, 3).simple, const MixedNum(0, 1, 3));
expect(const MixedNum(2).simple, const MixedNum(2));
expect(const MixedNum(3, 1).simple, const MixedNum(4));
expect(const MixedNum(-3, 5, 5).simple, const MixedNum(-4));
expect(const MixedNum(1, 5, 2).simple, const MixedNum(3, 1, 2));
});
});
Expand All @@ -74,7 +81,6 @@ void main() {
expect(const MixedNum(0).toString(), '0');
expect(const MixedNum(3).toString(), '3');
expect(const MixedNum(0, 1, 3).toString(), '1/3');
expect(const MixedNum(-12, 3, 8).toString(), '-12 3/8');
expect(const MixedNum(3, 5, 4).toString(), '3 5/4');
});
});
Expand All @@ -83,13 +89,11 @@ void main() {
test('sorts MixedNums in a collection', () {
final orderedSet = SplayTreeSet<MixedNum>.of({
const MixedNum(0),
const MixedNum(-3, 1, 2),
const MixedNum(1, 2, 2),
const MixedNum(0, 7, 2),
const MixedNum(0, 1, 9),
});
expect(orderedSet.toList(), const [
MixedNum(-3, 1, 2),
MixedNum(0),
MixedNum(0, 1, 9),
MixedNum(1, 2, 2),
Expand Down

0 comments on commit e11f99f

Please sign in to comment.