changeset 6:14badf9104b9

shifts, rotations, division
author Paul (paul.d.anderson@comcast.net)
date Mon, 22 Mar 2010 20:20:05 -0700
parents c021ed211f89
children b304232c476c
files src/decimal/bcd.d
diffstat 1 files changed, 248 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/decimal/bcd.d	Sat Mar 20 21:38:22 2010 -0700
+++ b/src/decimal/bcd.d	Mon Mar 22 20:20:05 2010 -0700
@@ -32,6 +32,7 @@
 
 module decimal.bcd;
 
+//import decimal.context: RoundingMode;
 import std.algorithm: max;
 import std.conv: ConvError;
 import std.math;
@@ -45,6 +46,19 @@
 public immutable Bcd NEG_ONE = { sign:true, digits:[1] };
 
 /**
+ * Enumeration of available rounding modes.
+ */
+public enum Rounding {
+	HALF_EVEN,
+	HALF_DOWN,
+	HALF_UP,
+	DOWN,
+	UP,
+	FLOOR,
+	CEILING,
+}
+
+/**
  * Provides BCD-encoded integral values of arbitrary length.
  *
  * Advantages of BCD:
@@ -205,6 +219,19 @@
 		digits.length = n;
 	}
 	
+unittest {
+	write("setWidth...");
+	Bcd a;
+	a = 1234567;
+	a.setNumDigits(5);
+	writeln("a = ", a);
+	assert(a == Bcd(34567));
+	a.setNumDigits(9);
+	writeln("a = ", a);
+	assert(a.toString == "000034567");
+	writeln("passed");
+}
+
 	/**
 	 * Returns the first digit of this BCD integer. If the
 	 * integer has leading zeros this function will return 
@@ -432,11 +459,31 @@
 	}
 	
 	Bcd opPostInc() {
-		return this + ONE;
+		this = this + ONE;
+		return this;
 	}
 	
 	Bcd opPostDec() {
-		return this - ONE;
+		this = this - ONE;
+		return this;
+	}
+	
+	const Bcd opShl(int n) {
+		return shift(this, n);
+	}
+	
+	Bcd opShlAssign(int n) {
+		this = this << n;
+		return this;
+	}
+	
+	const Bcd opShr(int n) {
+		return shift(this, -n);
+	}
+	
+	Bcd opShrAssign(int n) {
+		this = this >> n;
+		return this;
 	}
 	
 //--------------------------------
@@ -829,6 +876,7 @@
 	return (a == 0 && b != 0) || (a != 0 && b == 0);
 }
 
+// TODO: watch the leading zeros
 public Bcd add(const Bcd x, const Bcd y) {
 	Bcd a = x.dup;
 	Bcd b = y.dup;
@@ -862,7 +910,7 @@
 		}
 		sum.sign = sign;
 	}
-	return sum;
+	return stripLeadingZeros(sum);
 }
 
 unittest {
@@ -1080,9 +1128,163 @@
 	writeln("passed");
 }
 
+public Bcd truncate(const Bcd a, int n) {
+/+	if (n <= 0) return ZERO.dup;
+	if (n >= a.numDigits) return a.dup;
+	Bcd b;
+	b.digits = a.digits[$-n..$].dup;
+	b.sign = a.sign;
+	return b;+/
+	Bcd dummy;
+	return truncate(a, n, dummy);
+}
+
+unittest {
+	write("truncate....");
+	Bcd a;
+	a = 1234567;
+	assert(truncate(a,3) == 123);
+	a = 10256;
+	assert(truncate(a,5) == 10256);
+	a = 8500;
+	assert(truncate(a,1) == 8);
+	a = -8500;
+	assert(truncate(a,1) == -8);
+	a = -8500;
+	assert(truncate(a,-1) == 0);
+	writeln("passed");
+}
+
+/** 
+ * Truncate to the specified number of digits
+ */
+public Bcd truncate(const Bcd a, int n, out Bcd r) {
+	if (n <= 0) {
+		r = stripLeadingZeros(a);
+		return ZERO.dup;
+	}
+	if (n >= a.numDigits) {
+		r = ZERO.dup;
+		return stripLeadingZeros(a);
+	}
+	Bcd b;
+	b.digits = a.digits[$-n..$].dup;
+	b.sign = a.sign;
+	r.digits = a.digits[0..$-n].dup;
+	return b;
+}
+
+unittest {
+	write("truncRem...");
+	Bcd a;
+	Bcd r;
+	a = 1234567;
+	assert(truncate(a, 3, r) == 123);
+	assert(r == 4567);
+	a = 10256;
+	assert(truncate(a,5,r) == 10256);
+	assert(r == 0);
+	a = 8500;
+	assert(truncate(a,1,r) == 8);
+	assert(r == 500);
+	a = -8500;
+	assert(truncate(a,1,r) == -8);
+	assert(r == 500);
+	a = -8500;
+//	writeln("truncate(a, 6, r) = ", truncate(a, 6, r));
+//	writeln("r = ", r);
+	assert(truncate(a,6,r) == -8500);
+	assert(r == 0);
+	writeln("passed");
+}
+
+public Bcd pad(Bcd a, int n) {
+	if (n <= a.numDigits) return a.dup;
+	return Bcd(a,n);
+}
+
+unittest {
+	write("pad.........");
+	Bcd a;
+	a = 1234567;
+	assert(pad(a,3) == 1234567);
+	a = 10256;
+//	writeln("pad(a,9) = ", pad(a,9));
+	assert(pad(a,9).toString == "000010256");
+	a = 8500;
+	assert(pad(a,6).toString == "008500");
+	a = -8500;
+	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;
+	
+	do {
+		multiple = next;
+//		writeln("multiple = ", multiple);
+		next <<= 1;
+//		writeln("next = ", next);
+	} while (next <= remainder && next > multiple);
+	
+	while (multiple >= divisor) {
+		quotient <<= 1;
+//		writeln("quotient = ", quotient);
+		while (multiple <= remainder) {
+			remainder -= multiple;
+			writeln("remainder = ", remainder);
+			quotient++;
+//			writeln("quotient = ", quotient);
+		}
+		multiple >>= 1;
+//		writeln("multiple = ", multiple);
+	}
+	return quotient;
+}
+
+unittest {
+	write("divide...");
+	writeln();
+	Bcd a, b, q, r;
+	a = 144;
+	b = 12;
+	q = divide(a, b, r);
+	assert(q == 12);
+	assert(r == 0);
+	a = 144;
+	b = 14;
+	q = divide(a, b, r);
+	assert(q == 10);
+	assert(r == 4);
+	a = 142351;
+	b = 12;
+	q = divide(a, b, r);
+	writeln("q = ", q);
+	writeln("r = ", r);
+	assert(q == 11862);
+	assert(r == 7);
+	a = 2;
+	b = 12;
+	q = divide(a, b, r);
+	assert(q == 0);
+	assert(r == 2);
+	writeln("passed");
+}
+
+
 public Bcd pow10(const Bcd a, uint n) {
-	Bcd b = a.dup;
-	if (n == 0) return b;
+	Bcd b = stripLeadingZeros(a);
+	if (n == 0 || b == 0) return b;
 	Digit[] zeros = new Digit[n];
 	b.digits = zeros ~ b.digits;
 	return b;
@@ -1106,13 +1308,45 @@
 }
 
 public Bcd shift(const Bcd a, int n) {
+	if (n == 0) return stripLeadingZeros(a);
+	if (n > 0) {	// shift left
+		return pow10(a, n);
+	}
+	else {			// shift right
+		if (-n >= a.numDigits) return ZERO.dup;
+		return truncate(a, a.numDigits + n);
+	}
+}
+
+unittest {
+	write("shift.......");
+	Bcd a, b;
+	a = 1234;
+	b = shift(a, 1);
+	assert(b.toString == "12340");
+	b = shift(a, 2);
+	assert(b.toString == "123400");
+	b = shift(a, -1);
+//	writeln("b = ", b);
+	assert(b.toString == "123");
+	b = shift(a, 0);
+	assert(b.toString == "1234");
+	b = shift(a, -12);
+/+	writeln("b = ", b);+/
+	assert(b.toString == "0");
+	b = shift(a, -4);
+	assert(b.toString == "0");
+	writeln("passed");
+}
+
+public Bcd shiftFixed(const Bcd a, int n) {
 	if (n == 0) return a.dup;
 	Bcd b = Bcd(0, a.numDigits);
 	if (std.math.abs(n) >= a.numDigits) return b; 
-	if (n > 0) {	// shift left
+	if (n > 0) {	// shiftFixed left
 		b.digits[0..$-n] = a.digits[n..$];
 	}
-	else {			// shift right
+	else {			// shiftFixed right
 		n = -n;
 		b.digits[n..$] = a.digits[0..$-n];
 	}
@@ -1120,20 +1354,20 @@
 }
 
 unittest {
-	write("shift...");
+	write("shiftFixed...");
 	Bcd a, b;
 	a = 1234;
-	b = shift(a, 1);
+	b = shiftFixed(a, 1);
 	assert(b.toString == "0123");
-	b = shift(a, 2);
+	b = shiftFixed(a, 2);
 	assert(b.toString == "0012");
-	b = shift(a, -1);
+	b = shiftFixed(a, -1);
 	assert(b.toString == "2340");
-	b = shift(a, 0);
+	b = shiftFixed(a, 0);
 	assert(b.toString == "1234");
-	b = shift(a, 12);
+	b = shiftFixed(a, 12);
 	assert(b.toString == "0000");
-	b = shift(a, -4);
+	b = shiftFixed(a, -4);
 	assert(b.toString == "0000");
 	writeln("passed");
 }