[Scummvm-cvs-logs] SF.net SVN: scummvm:[55839] scummvm/trunk

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Wed Feb 9 01:12:03 CET 2011


Revision: 55839
          http://scummvm.svn.sourceforge.net/scummvm/?rev=55839&view=rev
Author:   fingolfin
Date:     2011-02-09 00:12:02 +0000 (Wed, 09 Feb 2011)

Log Message:
-----------
COMMON: Reduce overflow risk in Common::Rational += and -= operators

Modified Paths:
--------------
    scummvm/trunk/common/rational.cpp
    scummvm/trunk/test/common/rational.h

Modified: scummvm/trunk/common/rational.cpp
===================================================================
--- scummvm/trunk/common/rational.cpp	2011-02-09 00:11:39 UTC (rev 55838)
+++ scummvm/trunk/common/rational.cpp	2011-02-09 00:12:02 UTC (rev 55839)
@@ -57,7 +57,7 @@
 	// Cancel the fraction by dividing both the num and the denom
 	// by their greatest common divisor.
 
-	int gcd = Common::gcd(_num, _denom);
+	const int gcd = Common::gcd(_num, _denom);
 
 	_num   /= gcd;
 	_denom /= gcd;
@@ -78,18 +78,30 @@
 }
 
 Rational &Rational::operator+=(const Rational &right) {
-	_num   = _num * right._denom + right._num * _denom;
-	_denom = _denom * right._denom;
+	// Cancel common factors to avoid unnecessary overflow.
+	// Note that the result is *not* always normalized.
+	const int gcd = Common::gcd(_denom, right._denom);
 
+	_num    = _num * (right._denom / gcd);
+	_denom  = _denom / gcd;
+	_num   += right._num * _denom;
+	_denom *= right._denom;
+
 	cancel();
 
 	return *this;
 }
 
 Rational &Rational::operator-=(const Rational &right) {
-	_num   = _num * right._denom - right._num * _denom;
-	_denom = _denom * right._denom;
+	// Cancel common factors to avoid unnecessary overflow.
+	// Note that the result is *not* always normalized.
+	const int gcd = Common::gcd(_denom, right._denom);
 
+	_num    = _num * (right._denom / gcd);
+	_denom  = _denom / gcd;
+	_num   -= right._num * _denom;
+	_denom *= right._denom;
+
 	cancel();
 
 	return *this;
@@ -98,8 +110,8 @@
 Rational &Rational::operator*=(const Rational &right) {
 	// Cross-cancel to avoid unnecessary overflow;
 	// the result then is automatically normalized
-	int gcd1 = Common::gcd(_num, right._denom);
-	int gcd2 = Common::gcd(right._num, _denom);
+	const int gcd1 = Common::gcd(_num, right._denom);
+	const int gcd2 = Common::gcd(right._num, _denom);
 
 	_num   = (_num    / gcd1) * (right._num    / gcd2);
 	_denom = (_denom  / gcd2) * (right._denom  / gcd1);

Modified: scummvm/trunk/test/common/rational.h
===================================================================
--- scummvm/trunk/test/common/rational.h	2011-02-09 00:11:39 UTC (rev 55838)
+++ scummvm/trunk/test/common/rational.h	2011-02-09 00:12:02 UTC (rev 55839)
@@ -86,6 +86,22 @@
 		TS_ASSERT_EQUALS(r1 - 1, Common::Rational(-1, 2));
 	}
 
+	void test_add_sub2() {
+		// Make sure cancelation works correctly
+		const Common::Rational r0(4, 15);	// = 8 / 30
+		const Common::Rational r1(1, 6);	// = 5 / 30
+
+		TS_ASSERT_EQUALS(r0 + r1, Common::Rational(13, 30));
+		TS_ASSERT_EQUALS(r1 + r0, Common::Rational(13, 30));
+		TS_ASSERT_EQUALS(r0 - r1, Common::Rational(1, 10));
+		TS_ASSERT_EQUALS(r1 - r0, Common::Rational(-1, 10));
+
+		TS_ASSERT_EQUALS(1 + r1, Common::Rational(7, 6));
+		TS_ASSERT_EQUALS(r1 + 1, Common::Rational(7, 6));
+		TS_ASSERT_EQUALS(1 - r1, Common::Rational(5, 6));
+		TS_ASSERT_EQUALS(r1 - 1, Common::Rational(-5, 6));
+	}
+
 	void test_mul() {
 		const Common::Rational r0(6, 3);
 		const Common::Rational r1(1, 2);


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list