changeset 7:b304232c476c

Coded and tested div and mod. Changed setNumDigits.
author Paul (paul.d.anderson@comcast.net)
date Tue, 23 Mar 2010 20:50:07 -0700
parents 14badf9104b9
children c991b9fde45c
files src/decimal/bcd.d
diffstat 1 files changed, 128 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/src/decimal/bcd.d	Mon Mar 22 20:20:05 2010 -0700
+++ b/src/decimal/bcd.d	Tue Mar 23 20:50:07 2010 -0700
@@ -213,10 +213,18 @@
 	
 	/**
 	 * Adjusts the number of digits in this BCD integer,
-	 * padding or truncating if necessary.
+	 * padding or truncating if necessary. 
+	 * If truncating, first leading zeros are stripped away, then
+	 * the remainder is clipped.
 	 */
 	void setNumDigits(uint n) {
-		digits.length = n;
+		this = stripLeadingZeros(this);
+		if (n > digits.length) {
+			digits.length = n;
+		}
+		else {
+			this = truncate(this, n);
+		}
 	}
 	
 unittest {
@@ -224,11 +232,9 @@
 	Bcd a;
 	a = 1234567;
 	a.setNumDigits(5);
-	writeln("a = ", a);
-	assert(a == Bcd(34567));
+	assert(a == Bcd(12345));
 	a.setNumDigits(9);
-	writeln("a = ", a);
-	assert(a.toString == "000034567");
+	assert(a.toString == "000012345");
 	writeln("passed");
 }
 
@@ -267,7 +273,8 @@
 	
 	unittest {
 		write("digits...");
-		Bcd bcd = Bcd(12345678L);
+		Bcd bcd;
+		bcd = 12345678;
 		assert(bcd.numDigits() == 8);
 		assert(bcd.firstDigit() == 1);
 		assert(bcd.lastDigit() == 8);
@@ -279,8 +286,7 @@
 		assert(bcd.firstDigit() == 0);
 		assert(bcd.getDigit(5) == 7);
 		bcd.setNumDigits(5);
-		assert(bcd.getDigit(2) == 6);
-//		writeln("bcd = ", bcd);
+		assert(bcd.getDigit(2) == 3);
 		writeln("passed");
 	}
 	
@@ -529,18 +535,68 @@
 		return this;
 	}
 
-unittest {
-	write("multiply...");
-	Bcd a, b, c;
-	a = 105, b = -22;
-	c = a * b;
-	assert(c == -2310);
-	c = 45;
-	c *= 1205;
-//	writeln("c = ", c);
-	assert(c == 54225);
-	writeln("passed");
-}
+	unittest {
+		write("multiply...");
+		Bcd a, b, c;
+		a = 105, b = -22;
+		c = a * b;
+		assert(c == -2310);
+		c = 45;
+		c *= 1205;
+	//	writeln("c = ", c);
+		assert(c == 54225);
+		writeln("passed");
+	}
+
+	const Bcd opDiv(T:Bcd)(const T b) {
+		Bcd rem;
+		return divide(this, b, rem);
+	}
+	
+	unittest {
+		write("opDiv...");
+		Bcd a, b;
+		a = 7;
+		b = 3;
+		assert(a/b == 2);
+		writeln("passed");
+	}
+	
+	const Bcd opDiv(T)(const T b) {
+		Bcd rem;
+		return divide(this, Bcd(b), rem);
+	}
+	
+	Bcd opDivAssign(T)(const T b) {
+		this = this / b;
+		return this;
+	}
+
+	const Bcd opMod(T:Bcd)(const T b) {
+		Bcd rem;
+		divide(this, b, rem);
+		return rem;
+	}
+	
+	unittest {
+		write("opMod...");
+		Bcd a, b;
+		a = 7;
+		b = 3;
+		assert(a % b == 1);
+		writeln("passed");
+	}
+	
+	const Bcd opMod(T)(const T b) {
+		Bcd rem;
+		divide(this, Bcd(b), rem);
+		return rem;
+	}
+	
+	Bcd opModAssign(T)(const T b) {
+		this = this % b;
+		return this;
+	}
 
 	const Bcd opAnd(const Bcd a) {
 		return and(this, a);
@@ -724,6 +780,8 @@
 	return 0;
 }
 	
+	// TODO: does this need a const and a dup?
+	// should it be public?? private would be okay
 public Bcd stripLeadingZeros(const Bcd a) {
 	Bcd d = a.dup;
 	if (!a.hasLeadingZeros) return d;
@@ -732,7 +790,7 @@
 	while(i < len-1 && a.getDigit(i) == 0) {
 		i++;
 	} 
-	d.setNumDigits(len - i);
+	d.digits.length = (len-i); // - 1);
 	if (d.numDigits == 1 && d.firstDigit == 0) {
 		d.sign = false;
 	}
@@ -1217,44 +1275,41 @@
 	assert(pad(a,6).toString == "-008500");
 	writeln("passed");
 }
-public Bcd divide(const Bcd a, const Bcd b, out Bcd remainder) {
-	Bcd quotient;
-	Bcd dividend = stripLeadingZeros(a);
-//	writeln("dividend = ", dividend);
-	Bcd divisor = stripLeadingZeros(b);
-//	writeln("divisor = ", divisor);
-	if (divisor == ZERO) throw new Exception("Divide by zero");
-	remainder = dividend;
-	writeln("remainder = ", remainder);
-	Bcd next = divisor;
-//	writeln("next = ", next);
-	Bcd multiple;
+public Bcd divide(const Bcd a, const Bcd b, out Bcd r) {
+
+	if (b == ZERO) throw new Exception("Divide by zero");
+	if (a == ZERO) return ZERO.dup;
 	
+	Bcd d = stripLeadingZeros(abs(b));
+	r = stripLeadingZeros(abs(a));
+	Bcd q;
+	Bcd p = d;
+	Bcd m;
+	
+	// shift the divisor
 	do {
-		multiple = next;
-//		writeln("multiple = ", multiple);
-		next <<= 1;
-//		writeln("next = ", next);
-	} while (next <= remainder && next > multiple);
+		m = p;
+		p <<= 1;
+	} while (p <= r && p > m);
 	
-	while (multiple >= divisor) {
-		quotient <<= 1;
-//		writeln("quotient = ", quotient);
-		while (multiple <= remainder) {
-			remainder -= multiple;
-			writeln("remainder = ", remainder);
-			quotient++;
-//			writeln("quotient = ", quotient);
+	while (m >= d) {
+		q <<= 1;
+		// subtract repeatedly
+		while (m <= r) {
+			r -= m;
+			q++;
 		}
-		multiple >>= 1;
-//		writeln("multiple = ", multiple);
+		m >>= 1;
 	}
-	return quotient;
+	
+	// adjust the sign
+	r.sign = a.sign;
+	q.sign = a.sign != b.sign;
+	return q;
 }
 
 unittest {
 	write("divide...");
-	writeln();
 	Bcd a, b, q, r;
 	a = 144;
 	b = 12;
@@ -1269,8 +1324,8 @@
 	a = 142351;
 	b = 12;
 	q = divide(a, b, r);
-	writeln("q = ", q);
-	writeln("r = ", r);
+//	writeln("q = ", q);
+//	writeln("r = ", r);
 	assert(q == 11862);
 	assert(r == 7);
 	a = 2;
@@ -1278,6 +1333,26 @@
 	q = divide(a, b, r);
 	assert(q == 0);
 	assert(r == 2);
+	a = 7;
+	b = 3;
+	q = divide(a, b, r);
+	assert(q == 2);
+	assert(r == 1);
+	a = 7;
+	b = -3;
+	q = divide(a, b, r);
+	assert(q == -2);
+	assert(r == 1);
+	a = -7;
+	b = 3;
+	q = divide(a, b, r);
+	assert(q == -2);
+	assert(r == -1);
+	a = -7;
+	b = -3;
+	q = divide(a, b, r);
+	assert(q == 2);
+	assert(r == -1);
 	writeln("passed");
 }