changeset 10:f925fe996255

added cast, clip, power
author Paul (paul.d.anderson@comcast.net)
date Thu, 25 Mar 2010 20:05:00 -0700
parents 48d564218e05
children 8e5f172ec55c
files src/decimal/bcd.d
diffstat 1 files changed, 150 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/decimal/bcd.d	Wed Mar 24 22:21:38 2010 -0700
+++ b/src/decimal/bcd.d	Thu Mar 25 20:05:00 2010 -0700
@@ -32,7 +32,6 @@
 
 module decimal.bcd;
 
-//import decimal.context: RoundingMode;
 import std.algorithm: max;
 import std.conv: ConvError;
 import std.math;
@@ -45,6 +44,11 @@
 public immutable Bcd ONE  = { digits:[1] };
 public immutable Bcd NEG_ONE = { sign:true, digits:[1] };
 
+/+static this() {
+	immutable(Bcd) MAX_LONG = cast(immutable) Bcd(long.max);
+//	MAX_LONG = cast(immutable) Bcd(long.max);
+	}+/
+
 /**
  * Enumeration of available rounding modes.
  */
@@ -218,6 +222,17 @@
 	 * the remainder is clipped.
 	 */
 	void setNumDigits(uint n) {
+		if (n == 0) n++;
+		digits.length = n;
+	}
+
+/+	/**
+	 * Adjusts the number of digits in this BCD integer,
+	 * padding or truncating if necessary. 
+	 * If truncating, first leading zeros are stripped away, then
+	 * the remainder is clipped.
+	 */
+	void setNumDigits(uint n) {
 		stripl(this);
 		if (n > digits.length) {
 			digits.length = n;
@@ -225,9 +240,9 @@
 		else {
 			this = truncate(this, n);
 		}
-	}
+	}+/
 	
-unittest {
+/+unittest {
 	write("setWidth...");
 	Bcd a;
 	a = 1234567;
@@ -236,7 +251,7 @@
 	a.setNumDigits(9);
 	assert(a.toString == "000012345");
 	writeln("passed");
-}
+}+/
 
 	/**
 	 * Returns the first digit of this BCD integer. If the
@@ -271,7 +286,7 @@
 		digits[$-n-1] = value;
 	}
 	
-	unittest {
+/+	unittest {
 		write("digits...");
 		Bcd bcd;
 		bcd = 12345678;
@@ -288,7 +303,7 @@
 		bcd.setNumDigits(5);
 		assert(bcd.getDigit(2) == 3);
 		writeln("passed");
-	}
+	}+/
 	
 //--------------------------------
 // Common object functions.
@@ -381,6 +396,42 @@
 	}
 	
 //--------------------------------
+// casting operators.
+//-------------------------------- 
+
+	const long opCast() {
+		Bcd MAX_LONG = Bcd(long.max);
+		Bcd MIN_LONG = Bcd(long.min);
+
+		if (this > MAX_LONG || this < MIN_LONG)
+			throw new Exception("Can't cast -- out of range");
+		
+		long n = 0;
+		foreach_reverse(Digit digit; digits) {
+			n = 10*n + digit;
+		}
+		return this.sign ? -n : n;
+	}
+	
+	unittest {
+	write("cast(long)...");
+	Bcd a;
+	a = "12345678901234567890123456";
+//	long n = cast(long) a;
+	a = 12345678L;
+	long n = cast(long) a;
+	assert(n == 12345678L);
+	int m = cast(int) a;
+	assert(m == 12345678L);
+	a = -a;
+	m = cast(int) a;
+	assert(m == -12345678L);
+	
+	writeln("passed");
+}
+
+
+//--------------------------------
 // Assignment operators.
 //-------------------------------- 
 
@@ -615,6 +666,15 @@
 		a = 100;
 		b = 5;
 		assert(a > b);
+		a = -100;
+		b = 5;
+		assert(a < b);
+		a = -100;
+		b = -5;
+		assert(a < b);
+		a = 100;
+		b = -5;
+		assert(a > b);
 		a = 5;
 		b = 100;
 		assert(a < b);
@@ -665,7 +725,7 @@
 	// no leading zeros
 	if (a.hasLeadingZeros) return false;
 	// not -0
-	if (a.numDigits == 1 && a.firstDigit == 0) return !a.sign;
+/+	if (a.numDigits == 1 && a.firstDigit == 0) return !a.sign;+/
 	return true;
 }
 
@@ -674,12 +734,44 @@
 	Bcd d = a.dup;
 	if (isCanonical(a)) return d;
 	stripl(d);
-	if (d.numDigits == 1 && d.firstDigit == 0) {
+/+	if (d.numDigits == 1 && d.firstDigit == 0) {
 		d.sign = false;
-	}
+	}+/
 	return d;
 }
 
+
+private void clipFirst(ref Bcd a, uint n = 1) {
+	if (n == 0) return;
+	if (n >= a.digits.length) a = ZERO;
+	else a.digits = a.digits[0..$-n];
+}
+
+private void clipLast(ref Bcd a, uint n = 1) {
+	if (n == 0) return;
+	if (n >= a.digits.length) a = ZERO;
+	else a.digits = a.digits[n..$];
+}
+
+unittest {
+	write("clipping....");
+	Bcd a;
+	a = 12345;
+	clipFirst(a);
+	assert(a == 2345);
+	clipLast(a);
+	assert(a == 234);
+	a = 1234567890;
+	clipFirst(a, 3);
+	assert(a == 4567890);
+	clipLast(a, 5);
+	assert(a == 45);
+	clipLast(a, 5);
+	assert(a == 0);
+	writeln("passed");
+}
+
+
 /**
  * Strips leading zeros from the specified decint.
  */
@@ -826,11 +918,21 @@
 	Bcd b = canonical(n);
 	if (!a.isSigned && b.isSigned) return 1;
 	if (a.isSigned && !b.isSigned) return -1;
-	if (a.digits.length > b.digits.length) return 1;
-	if (a.digits.length < b.digits.length) return -1;
-	foreach_reverse(int i, Digit digit; a.digits) {
-		if (digit > b.digits[i]) return 1;
-		if (digit < b.digits[i]) return -1;
+	if (!a.isSigned) {
+		if (a.digits.length > b.digits.length) return 1;
+		if (a.digits.length < b.digits.length) return -1;
+		foreach_reverse(int i, Digit digit; a.digits) {
+			if (digit > b.digits[i]) return 1;
+			if (digit < b.digits[i]) return -1;
+		}
+	}
+	else {
+		if (a.digits.length > b.digits.length) return -1;
+		if (a.digits.length < b.digits.length) return 11;
+		foreach_reverse(int i, Digit digit; a.digits) {
+			if (digit > b.digits[i]) return -1;
+			if (digit < b.digits[i]) return 1;
+		}
 	}
 	return 0;
 }
@@ -851,11 +953,11 @@
 	writeln("passed");
 }
 	
-public bool sameLength(const Bcd a, const Bcd b) {
+private bool sameLength(const Bcd a, const Bcd b) {
 	return a.numDigits == b.numDigits;
 }
 
-public int setSameLength(ref Bcd a, ref Bcd b) {
+private int setSameLength(ref Bcd a, ref Bcd b) {
 	if (sameLength(a, b)) return a.numDigits;
 	uint alen = a.numDigits;
 	uint blen = b.numDigits;
@@ -868,7 +970,8 @@
 	return a.numDigits();
 }
 
-public Bcd twosComp(const Bcd a) {
+// TODO: really? private?
+private Bcd twosComp(const Bcd a) {
 	Bcd b = Bcd(0, a.numDigits);
 	foreach(int i, Digit digit; a.digits) {
 		b.digits[i] = digit == 0 ? 1 : 0 ;
@@ -893,12 +996,12 @@
 	return bcd.isSigned ? -1 : 1;
 }
 
-public Bcd not(const Bcd x) {
-	Bcd result = cast(Bcd) x;
-	for (int i = 0; i < x.numDigits; i++) {
-		result[i] = not(result[i]);
+public Bcd not(const Bcd a) {
+	Bcd b = a.dup;
+	foreach(Digit digit; b.digits) {
+		digit = not(digit);
 	}
-	return result;
+	return b;
 }
 
 private Digit not(const Digit a) {
@@ -1309,8 +1412,7 @@
 
 
 public Bcd truncate(const Bcd a, int n) {
-	Bcd dummy;
-	return truncate(a, n, dummy);
+	return truncate(a, n, Bcd());
 }
 
 unittest {
@@ -1417,6 +1519,30 @@
 	writeln("passed");
 }
 
+public Bcd power(const Bcd a, uint n) {
+	Bcd b = canonical(a);
+	Bcd p = ONE.dup;
+	while (n > 0) {
+		if (n & 1) {
+			p *= b;
+			if (n == 1) return p;
+		}
+		b *= b;
+		n /= 2;
+	}
+	return p;
+}
+
+unittest {
+	write("power.......");
+	Bcd a;
+	a = 2;
+	int n = 3;
+	assert(power(a,n) == 8);
+	writeln("passed");
+}
+
+
 public Bcd shift(const Bcd a, int n) {
 	if (n == 0) return canonical(a);
 	if (n > 0) {	// shift left