From e11f99f2cf76d87c7a6747b6b4fb86aed6611d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Ma=C3=B1osa?= <26429103+albertms10@users.noreply.github.com> Date: Mon, 13 May 2024 23:57:19 +0200 Subject: [PATCH] =?UTF-8?q?feat(mixed=5Fnum):=20=F0=9F=94=A5=20drop=20supp?= =?UTF-8?q?ort=20for=20negative=20values?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Albert MaƱosa <26429103+albertms10@users.noreply.github.com> --- lib/src/utils/mixed_num.dart | 20 +++++++++++++------- test/utils/mixed_num_test.dart | 14 +++++++++----- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/lib/src/utils/mixed_num.dart b/lib/src/utils/mixed_num.dart index 77984ac3..c79771fe 100644 --- a/lib/src/utils/mixed_num.dart +++ b/lib/src/utils/mixed_num.dart @@ -1,5 +1,4 @@ import 'package:meta/meta.dart' show immutable; -import 'package:music_notes/utils.dart'; /// A mixed number representation. @immutable @@ -16,6 +15,10 @@ final class MixedNum implements Comparable { /// 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.', ), @@ -47,6 +50,9 @@ final class MixedNum implements Comparable { /// 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; @@ -56,13 +62,13 @@ final class MixedNum implements Comparable { 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; @@ -82,7 +88,7 @@ final class MixedNum implements Comparable { 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; diff --git a/test/utils/mixed_num_test.dart b/test/utils/mixed_num_test.dart index 51c52cbd..c4f7d777 100644 --- a/test/utils/mixed_num_test.dart +++ b/test/utils/mixed_num_test.dart @@ -9,6 +9,7 @@ void main() { test('throws an assertion error when arguments are incorrect', () { expect(() => MixedNum(1, -2), throwsA(isA())); expect(() => MixedNum(1, 1, 0), throwsA(isA())); + expect(() => MixedNum(-1), throwsA(isA())); }); }); @@ -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)); }); }); @@ -47,6 +47,14 @@ 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())); + expect( + () => MixedNum.fromDouble(1, tolerance: -1), + throwsA(isA()), + ); + }); }); group('.simple', () { @@ -54,7 +62,6 @@ void main() { 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)); }); }); @@ -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'); }); }); @@ -83,13 +89,11 @@ void main() { test('sorts MixedNums in a collection', () { final orderedSet = SplayTreeSet.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),