changeset 13:e871083087da default tip

removed module decimal.bcd
author Paul (paul.d.anderson@comcast.net)
date Thu, 25 Mar 2010 21:46:16 -0700
parents 526759f0ee1c
children
files src/decimal/bcd.d
diffstat 1 files changed, 0 insertions(+), 1762 deletions(-) [+]
line wrap: on
line diff
--- a/src/decimal/bcd.d	Thu Mar 25 21:43:40 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1762 +0,0 @@
-/** 
- * A D programming language implementation of the 
- * General Decimal Arithmetic Specification, 
- * Version 1.70, (25 March 2009).
- *
- * by Paul D. Anderson
- *
- * Boost Software License - Version 1.0 - August 17th, 2003
- *
- * Permission is hereby granted, free of charge, to any person or organization
- * obtaining a copy of the software and accompanying documentation covered by
- * this license (the "Software") to use, reproduce, display, distribute,
- * execute, and transmit the Software, and to prepare derivative works of the
- * Software, and to permit third-parties to whom the Software is furnished to
- * do so, all subject to the following:
- *
- * The copyright notices in the Software and this entire statement, including
- * the above license grant, this restriction and the following disclaimer,
- * must be included in all copies of the Software, in whole or in part, and
- * all derivative works of the Software, unless such copies or derivative
- * works are solely in the form of machine-executable object code generated by
- * a source language processor.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
- * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
- * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
-**/
-
-module decimal.bcd;
-
-import std.algorithm: max;
-import std.conv: ConvError;
-import std.math;
-import std.stdio: write, writeln;
-import std.string: strip;
-
-alias ubyte Digit;
-
-public immutable Bcd ZERO = { digits:[0] };
-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.
- */
-public enum Rounding {
-	HALF_EVEN,
-	HALF_DOWN,
-	HALF_UP,
-	DOWN,
-	UP,
-	FLOOR,
-	CEILING,
-}
-
-/**
- * Provides BCD-encoded integral values of arbitrary length.
- *
- * Advantages of BCD:
- * To/from string is easy.
- * Easy to pull values of individual digits.
- * Easy to multiply and divide by powers of 10.
- * 
- * Disadvantages of BCD:
- * Significantly less compact representation.
- * Operations are carried out bytewise, requiring more iterations.
- * Extra steps required for addition.
- *
- */
-public struct Bcd {
-
-//--------------------------------
-// members
-//-------------------------------- 
-
-	/**
-	 * The sign of the BCD integer. Sign is kept explicitly
-	 * and not encoded in the number.
-	 **/
-	private bool sign = false;
-	
-	/**
-	 * An array of decimal digits in reverse (right-to-left) order
-	 * representing an integral value. 
-	 * Trailing zeros have no effect on the value of the number;
-	 * they correspond to leading zeros in a left-to-right representation.
-	**/
-	private Digit[] digits = [ 0 ];
-	
-//--------------------------------
-// construction
-//-------------------------------- 
-
-	//--------------------------------
-	// copy construction
-	//-------------------------------- 
-
-
-	/**
-	 * Copy constructor. Returns a (non-const) copy of the argument.
-	 */
-	public this(const Bcd bcd) {
-		sign = bcd.sign;
-		digits = bcd.digits.dup;
-	}
-	
-	/**
-	 * Copies a BCD integer and adjusts the number of digits,
-	 * padding or turncating, if necessary.
-	 */
-	public this(const Bcd bcd, uint numDigits) {
-		this(bcd);
-		setNumDigits(numDigits);
-	}
-	
-	//--------------------------------
-	// construction from integer types.
-	//-------------------------------- 
-
-	/**
-	 * Constructs a BCD integer from a (signed) byte, short, int or long value.
-	 */
-	public this(const long n) {
-		ulong m;	
-		if (n < 0) {
-			sign = true;
-			m = std.math.abs(n);
-		}
-		else {
-			sign = false;
-			m = n;
-		}
-		Digit[20] dig;
-		int i = 0;
-		do {
-			ulong q = m/10;
-			ulong r = m%10;
-			dig[i] = cast(Digit) r;
-			m = q;
-			i++;
-		} while (m > 0);
-		digits = dig[0..i].dup;
-	}
-		
-	/**
-	 * Constructs a BCD integer from a (signed) byte, short,
-	 * int or long value, and then adjusts the number of digits,
-	 * padding or truncating as needed.
-	 */
-	public this(const long n, uint numDigits) {
-		this = n;
-		setNumDigits(numDigits);
-	}
-		
-	unittest {
-		write("this(long)..");
-		Bcd p;
-		p = -1234;
-		assert(p == Bcd("-1234"));
-		p = 12345678L;
-		assert(p == Bcd("12345678"));
-		p = Bcd(-19166586400L);
-		assert(p == Bcd("-19166586400"));
-		p = Bcd(139676498390L);
-		assert(p == Bcd("139676498390"));
-		writeln("passed");
-	}
-
-	//--------------------------------
-	// construction from a string.
-	//-------------------------------- 
-
-	/**
-	 * Constructs a BCD integer from a string representation.
-	 * If the string has leading zeros they are retained internally.
-	 */
-	public this(const string str) {
-		this = parse(str);
-	}
-	
-//--------------------------------
-// member access functions
-//-------------------------------- 
-
-	//--------------------------------
-	// access to the sign of the number
-	//-------------------------------- 
-
-	const bool isSigned() {
-		return sign;
-	}
-	
-	void setSign(bool sign) {
-		this.sign = sign;
-	}
-	
-	//--------------------------------
-	// access to the digits
-	//-------------------------------- 
-
-	/**
-	 * Returns the number of digits in this BCD integer.
-	 * Includes leading zero digits.
-	 */
-	const uint numDigits() {
-		return digits.length;
-	}
-	
-	/**
-	 * 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) {
-		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;
-		}
-		else {
-			this = truncate(this, n);
-		}
-	}+/
-	
-/+unittest {
-	write("setWidth...");
-	Bcd a;
-	a = 1234567;
-	a.setNumDigits(5);
-	assert(a == Bcd(12345));
-	a.setNumDigits(9);
-	assert(a.toString == "000012345");
-	writeln("passed");
-}+/
-
-	/**
-	 * Returns the first digit of this BCD integer. If the
-	 * integer has leading zeros this function will return 
-	 * zero, but the value of the number is not necessarily zero.
-	 */
-	const uint firstDigit() {
-		return digits[$-1];
-	}
-	
-	/**
-	 * Returns the last digit of this BCD integer.
-	 */
-	const uint lastDigit() {
-		return digits[0];
-	}
-	
-	/**
-	 * Returns the specified digit of this BCD integer. The index is 
-	 * zero based, i.e., getDigit(0) returns the first digit.
-	 */
-	const int getDigit(int n) {
-		return digits[$-n-1];
-	}
-	
-	/**
-	 * Sets the specified digit of this BCD integer to the specified value.
-	 * The index is zero based, i.e., getDigit(0) returns the first digit.
-	 */
-	void setDigit(uint n, Digit value) {
-		assert(value < 10);
-		digits[$-n-1] = value;
-	}
-	
-/+	unittest {
-		write("digits...");
-		Bcd bcd;
-		bcd = 12345678;
-		assert(bcd.numDigits() == 8);
-		assert(bcd.firstDigit() == 1);
-		assert(bcd.lastDigit() == 8);
-		assert(bcd.getDigit(3) == 4);
-		bcd.setDigit(3, 7);
-		assert(bcd.getDigit(3) == 7);
-		bcd.setNumDigits(10);
-		assert(bcd.numDigits == 10);
-		assert(bcd.firstDigit() == 0);
-		assert(bcd.getDigit(5) == 7);
-		bcd.setNumDigits(5);
-		assert(bcd.getDigit(2) == 3);
-		writeln("passed");
-	}+/
-	
-//--------------------------------
-// Common object functions.
-//-------------------------------- 
-
-	/**
-	 * Returns a string representation of this BCD integer.
-	 * Leading zeros are displayed. The sign is displayed if
-	 * the number is negative.
-	 */
-	const string toString() {
-		return format(this);
-	}
-	
-	unittest {
-		write("toString...");
-		writeln("passed");
-	}
-	
-	/**
-	 * Returns a hash code for this BCD integer.
-	 */
-	const hash_t toHash() {
-		hash_t hash = 0;
-		foreach(Digit digit; digits) {
-			hash += digit;
-		}
-		return hash;
-	}
-	
-	unittest {
-		write("toHash...");
-		writeln("passed");
-	}
-	
-	/**
-	 * Returns a mutable copy of this BCD integer.
-	 */
-	const Bcd dup() {
-		Bcd bcd;
-		bcd.sign = this.sign;
-		bcd.digits = digits.dup;
-		return bcd;
-	}
-	
-//--------------------------------
-// Utility functions.
-//-------------------------------- 
-
-	/**
-	 * Returns true if the internal representation of
-	 * this BCD integer has leading zeros.
-	 */
-	const bool hasLeadingZeros() {
-		return numDigits > 1 && firstDigit == 0;
-	}
-	
-	unittest {
-	write("hasLeadingZeros...");
-	assert(!ZERO.hasLeadingZeros);
-	Bcd b = Bcd(0);
-	assert(!b.hasLeadingZeros);
-	b = "-00000001";
-	assert(b.hasLeadingZeros);
-	b = "-00000000";
-	assert(b.hasLeadingZeros);
-	writeln("passed");
-	}
-	
-	/**
-	 * Returns true if the value of this BCD integer is zero.
-	 * Ignores leading zeros and sign.
-	 */
-	const bool isZero() {
-		Bcd b = canonical(this);
-		if (b.numDigits > 1) return false;
-		return b.lastDigit == 0;
-	}
-	
-	unittest {
-	write("isZero.........");
-	assert(ZERO.isZero);
-	Bcd b = Bcd(0);
-	assert(b.isZero);
-	b = "-00000001";
-	assert(!b.isZero);
-	b = "-00000000";
-	assert(b.isZero);
-	writeln("passed");
-	}
-	
-//--------------------------------
-// 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.
-//-------------------------------- 
-
-	/**
-	 * Assignment operator for BCD integer to BCD integer operations.
-	 */
-	Bcd opAssign(const Bcd that) {
-		this.sign = that.sign;
-		this.digits = that.digits.dup;
-		return this;
-	}
-	
-	/**
-	 * Converts the string argument into a BCD integer and assigns it 
-	 * to this BCD integer.
-	 */
-	void opAssign(const string str) {
-		this = Bcd(str);
-	}
-	
-	/**
-	 * Converts the integer argument into a BCD integer and assigns it 
-	 * to this BCD integer.
-	 */
-	void opAssign(const long n) {
-		this = Bcd(n);
-	}
-	
-	
-	// index operator
-	Digit opIndex(uint index) {
-		return this.digits[index];
-	}
-	
-	// index assign operator
-	void opIndexAssign(Digit value, uint index) {
-		this.digits[index] = value;
-	}
-	
-//--------------------------------
-// unary operators
-//-------------------------------- 
-	
-	const Bcd opPos() {
-		return this.dup;
-	}
-	
-	const Bcd opNeg() {
-		return negate(this);
-	}
-	
-	const Bcd opCom() {
-		return twosComp(this);
-	}
-	
-	const Bcd opNot() {
-		return not(this);
-	}
-	
-	Bcd opPostInc() {
-		this = this + ONE;
-		return this;
-	}
-	
-	Bcd opPostDec() {
-		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;
-	}
-	
-//--------------------------------
-// binary operators
-//-------------------------------- 
-	
-	const Bcd opAdd(T:Bcd)(const T addend) {
-		return add(this, addend);
-	}
-	
-	const Bcd opAdd(T)(const T addend) {
-		return add(this, Bcd(addend));
-	}
-	
-	Bcd opAddAssign(T)(const T addend) {
-		this = this + addend;
-		return this;
-	}
-
-	const Bcd opSub(T:Bcd)(const T addend) {
-		return subtract(this, addend);
-	}
-	
-	const Bcd opSub(T)(const T addend) {
-		return subtract(this, Bcd(addend));
-	}
-	
-	Bcd opSubAssign(T)(const T addend) {
-		this = this - addend;
-		return this;
-	}
-
-	const Bcd opMul(T:Bcd)(const T b) {
-		return multiply(this, b);
-	}
-	
-	const Bcd opMul(T)(const T b) {
-		return multiply(this, Bcd(b));
-	}
-	
-	Bcd opMulAssign(T)(const T b) {
-		this = this * b;
-		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");
-	}
-
-	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);
-	}
-	
-	Bcd opAndAssign(const Bcd a) {
-		this = this & a;
-		return this;
-	}
-
-	const Bcd opOr(const Bcd a) {
-		return or(this, a);
-	}
-	
-	Bcd opOrAssign(const Bcd a) {
-		this = this | a;
-		return this;
-	}
-
-	const Bcd opXor(const Bcd a) {
-		return xor(this, a);
-	}
-	
-	Bcd opXorAssign(const Bcd a) {
-		this = this ^ a;
-		return this;
-	}
-
-//--------------------------------
-// comparison, equality operators
-//-------------------------------- 
-	
-	const int opCmp(T:Bcd)(const T that) {
-		return compare(this, that);
-	}
-	
-	unittest {
-		write("compare...");
-		Bcd a,b;
-		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);
-		assert(b > a);
-		writeln("passed");
-	}
-	
-	const int opCmp(T)(const T that) {
-		return opCmp(Bcd(that));
-	}
-	
-	const bool opEquals(T:Bcd)(const T that) {
-		Bcd a = comparable(this);
-		Bcd b = comparable(that);
-		if (this.sign != that.sign) return false;
-		if (a.digits.length != b.digits.length) return false;
-		foreach_reverse(int i, Digit digit; a.digits) {
-			if (digit != b.digits[i]) return false;
-		}
-		return true;
-	}
-	
-	const bool opEquals(T)(const T that) {
-		return opEquals(Bcd(that));
-	}
-
-	unittest {
-	write("equals...");	
-	assert(Bcd(0) == Bcd(0));
-	assert(Bcd(4) == Bcd(4));
-	assert(Bcd(40) == Bcd(40));
-	assert(Bcd(-400) == Bcd(-400));
-	assert(Bcd(12345678) == Bcd(+12345678));
-	assert(Bcd(40) != Bcd(53));
-	assert(Bcd(402) != Bcd(531));
-	assert(Bcd(402) != Bcd(-402));
-    assert(Bcd(65432) != Bcd(65431));
-	assert(Bcd(2) != Bcd(1));
-	assert(Bcd(1) != Bcd(2));
-	writeln("passed");
-	}
-	
-} // end struct Bcd
-
-
-public bool isCanonical(const Bcd a) {
-	// no leading zeros
-	return !a.hasLeadingZeros;
-}
-
-// Strips leading zeros
-public Bcd canonical(const Bcd a) {
-	Bcd d = a.dup;
-	if (isCanonical(a)) return d;
-	stripl(d);
-	return d;
-}
-
-// Strips leading zeros and changes sign if == -0
-private Bcd comparable(const Bcd a) {
-	Bcd d = canonical(a);
-	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.
- */
-private void stripl(ref Bcd a) {
-	if (a.hasLeadingZeros) {
-		foreach_reverse(int i, Digit digit; a.digits) {
-			if (i == 0 || digit != 0) {
-				a.digits.length = i+1;
-				break;
-			}
-		}
-	} 
-}
-
-unittest {
-	write("stripl......");
-	Bcd b = Bcd("+00023");
-	assert(b.toString == "00023");
-	stripl(b);
-	assert(b.toString == "23");
-	b = "-00050432";
-	stripl(b);
-	assert(b.toString == "-50432");
-	b = "-000";
-	stripl(b);
-	assert(b.toString == "-0");
-	writeln("passed");
-}
-
-/**
- * Strips trailing zeros from the specified decint.
- */
-private void stripr(ref Bcd a) {
-	int len = a.digits.length;
-	foreach(int i, Digit digit; a.digits) {
-		if (i == len-1 || digit != 0) {
-			a.digits = a.digits[i..$];
-			break;
-		}
-	}
-}
-
-unittest {
-	write("stripl......");
-	Bcd b;
-	b = 23;
-	stripr(b);
-	assert(b == 23);
-	b = "-5000";
-	stripr(b);
-	assert(b.toString == "-5");
-	b = "-000";
-	stripr(b);
-	assert(b.toString == "-0");
-	writeln("passed");
-}
-
-//public string format(const Bcd bcd, bool showPlus = false, bool showLeadingZeros = false) {
-public string format(const Bcd bcd) {
-	int len = bcd.digits.length;
-	if (bcd.isSigned) len++;
-//	if (bcd.isSigned || bcd.hasLeadingZeros) len++;
-	char[] str = new char[len];
-	
-	int index = 0;
-	if (bcd.sign) {
-		str[index] = '-';
-		index++;
-	}
-/+	if (bcd.hasLeadingZeros) {
-		str[index] = '+';
-		index++;
-	}+/
-	foreach_reverse(Digit digit; bcd.digits) {
-		str[index] = cast(char) digit + '0';
-		index++;
-	}
-	return str.idup;
-}
-
-public Bcd parse(string str) {
-	Bcd bcd;
-	// are leading zeros retained?
-	bool lz = false;
-
-	// strip whitespace, convert to char array
-	char[] str1 = str.strip.dup;
-	
-	// check for leading '-'
-	if (str1[0] == '-') {
-		bcd.sign = true;
-		str1 = str1[1..$];
-		lz = true;
-	}
-	
-	// check for leading '+'
-	if (str1[0] == '+') {
-		bcd.sign = false;
-		str1 = str1[1..$];
-		lz = true;
-	}
-	
-	// verify chars are digits, strip out underscores
-	int index = 0;
-	char[] str2 = new char[str1.length];
-	foreach_reverse(char ch; str1) {
-		if (isDigit(ch)) {
-			str2[index] = ch;
-			index++;
-			continue;
-	    }
-		if (ch == '_') {
-			continue;
-		}
-		throw (new ConvError("Invalid character: " ~ ch));
-	}
-	str2.length = index;
-	
-	bcd.digits.length = index;
-	foreach(int i, char ch; str2) {
-		bcd.digits[i] = cast(Digit)(ch - '0');
-	}
-
-	if (!lz) return canonical(bcd);	
-	return bcd;
-}
-
-private bool isDigit(const char ch) {
-	return (ch >= '0' && ch <= '9');
-}
-
-public Bcd negate(const Bcd a) {
-	Bcd b = a.dup;
-	b.sign = !a.sign;
-	return b;
-}
-
-public Bcd abs(const Bcd a) {
-	return a.isSigned ? -a: +a;
-}
-
-public int compare(const Bcd m, const Bcd n) {
-	Bcd a = comparable(m);
-	Bcd b = comparable(n);
-	if (!a.isSigned && b.isSigned) return 1;
-	if (a.isSigned && !b.isSigned) 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;
-}
-	
-unittest {
-	write("strip...");
-	Bcd bcd;
-	bcd = "+00123";
-	assert(bcd.toString == "00123");
-	bcd = canonical(bcd);
-//	writeln("bcd = ", bcd);
-	assert(bcd.toString == "123");
-	bcd = "+000";
-//	writeln("bcd = ", bcd);
-	assert(bcd.toString == "000");
-	bcd = canonical(bcd);
-//	writeln("bcd = ", bcd);
-	writeln("passed");
-}
-	
-private bool sameLength(const Bcd a, const Bcd b) {
-	return a.numDigits == b.numDigits;
-}
-
-private int setSameLength(ref Bcd a, ref Bcd b) {
-	if (sameLength(a, b)) return a.numDigits;
-	uint alen = a.numDigits;
-	uint blen = b.numDigits;
-	if (alen > blen) {
-		b.setNumDigits(alen);
-	}
-	else {
-		a.setNumDigits(blen);
-	}
-	return a.numDigits();
-}
-
-// 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 ;
-	}
-	return b;
-}
-
-unittest {
-	write("com...");
-	Bcd bcd;
-	bcd = 123;
-	assert(twosComp(bcd).toString == "000");
-	bcd = 40509;
-	assert(twosComp(bcd).toString == "01010");
-//	writeln("bcd = ", bcd);
-//	writeln("~bcd = ", twosComp(bcd));
-	writeln("passed");
-}
-	
-public int sgn(const Bcd bcd) {
-	if (bcd.isZero) return 0;
-	return bcd.isSigned ? -1 : 1;
-}
-
-public Bcd not(const Bcd a) {
-	Bcd b = a.dup;
-	foreach(Digit digit; b.digits) {
-		digit = not(digit);
-	}
-	return b;
-}
-
-private Digit not(const Digit a) {
-	return a != 0;
-}
-
-public Bcd and(const Bcd x, const Bcd y) {
-	Bcd a = x.dup;
-	Bcd b = y.dup;
-	int len = setSameLength(a,b);
-	Bcd result = Bcd(0, len);
-	for (int i = 0; i < len; i++) {
-		result[i] = and(a[i], b[i]);
-	}
-	return result;
-}
-
-private Digit and(const Digit a, const Digit b) {
-	return a != 0 && b != 0;
-}
-
-unittest {
-	write("and...");
-	Bcd a;
-	Bcd b;
-	a = 123000;
-	b = 123000;
-	assert(and(a,b).toString == "111000");
-	b = 12300;
-	assert(and(a,b).toString == "011000");
-	a = 1234567;
-	b = 7654321;
-	assert(and(a,b).toString == "1111111");
-	a = 1010;
-	b = 101;
-//	writeln("a = ", a);
-//	writeln("b = ", b);
-//	writeln("and = ", and(a,b));
-	assert(and(a,b).isZero);
-	writeln("passed");
-}
-
-// TODO: looks like there's some room for templates or mixins here.
-public Bcd or(const Bcd x, const Bcd y) {
-	Bcd a = x.dup;
-	Bcd b = y.dup;
-	int len = setSameLength(a,b);
-	Bcd result = Bcd(0, len);
-	for (int i = 0; i < len; i++) {
-		result[i] = or(a[i], b[i]);
-	}
-	return result;
-}
-
-private Digit or(const Digit a, const Digit b) {
-	return a != 0 || b != 0;
-}
-
-public Bcd xor(const Bcd x, const Bcd y) {
-	Bcd a = x.dup;
-	Bcd b = y.dup;
-	int len = setSameLength(a,b);
-	Bcd result = Bcd(0, len);
-	for (int i = 0; i < len; i++) {
-		result[i] = xor(a[i], b[i]);
-	}
-	return result;
-}
-
-private Digit xor(const Digit a, const Digit b) {
-	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;
-	Bcd sum;
-	if (a.sign == b.sign) {
-		sum = simpleAdd(a, b);
-		stripl(sum);
-		sum.sign = a.sign;
-		return sum;
-	}
-	else { // signs differ
-		bool sign;
-		switch (compare(abs(a), abs(b))) {
-			case 0:
-				return ZERO.dup;
-			case 1:
-				sign = a.isSigned;
-				break;
-			case -1:
-				sign = b.isSigned;
-				break;
-		}
-		setSameLength(a, b);
-		sum = simpleAdd(a, tensComp(b));
-		if (sum.firstDigit == 1) {
-			sum.digits = sum.digits[0..$-1];
-		}
-		else {
-			sum = tensComp(sum);
-		}
-		stripl(sum);
-		sum.sign = sign;
-	}
-	return sum;
-}
-
-unittest {
-	write("add....");
-	Bcd a, b;
-	a = 1234;
-	b = 4321;
-	assert(a + b == 5555);
-	a = 2000;
-	b = 1;
-	assert(a + b == 2001);
-	a = -2000;
-	b = -1;
-	assert(a + b == -2001);
-	a = 2000;
-	b = -1;
-	assert(a + b == 1999);
-	a = -123;
-	b = 1;
-	assert(a + b == -122);
-	a = 123;
-	b = -1;
-	assert(a + b == 122);
-	a = -1;
-	b = 123;
-//	writeln();
-//	writeln("a + b = ", a + b);
-	assert(a + b == 122);
-	a = -123;
-	b = 1;
-	assert(a + b == -122);
-	a = 1;
-	b = -123;
-	assert(a + b == -122);
-	writeln("passed");
-}
-
-Bcd subtract(const Bcd a, const Bcd b) {
-	return add(a, negate(b));
-}
-
-/**
- * Adds two BCD integers without regard to sign
-**/
-private Bcd simpleAdd(const Bcd a, const Bcd b) {
-	Bcd x = a.dup;
-	Bcd y = b.dup;
-	int len = setSameLength(x, y);
-	Bcd sum = Bcd(0, len+1);
-	Digit carry = 0;
-	uint i;
-	// TODO: this is the place to stop adding zeros and
-	// just copy the rest of the digits.
-	for (i = 0; i < len; i++) {
-		sum[i] = add(x[i], y[i], carry);
-	}
-	if (carry) {
-		sum[i] = 1;
-	}
-	else {
-		stripl(sum);
-	}
-	return sum;
-}
-
-// TODO: need a clipFirst, clipLast method
-
-/**
- * Adds two digits and a carry digit.
- * Returns the (single-digit) sum and sets or resets the carry digit.
-**/
-private Digit add(const Digit a, const Digit b, ref Digit carry) {
-	Digit sum = a + b + carry;
-	carry = sum > 9;
-	if (carry) sum -= 10;
-	return sum;
-}
-
-unittest {
-	write("simpleAdd...");
-	Bcd a, b;
-	a = 123;
-	b = 222;
-	Bcd sum = simpleAdd(a,b);
-	assert(sum == 345);
-	a = 2;
-	b = 102000;
-	sum = simpleAdd(a,b);
-	assert(sum == 102002);
-	writeln("passed");
-}
-
-private Bcd tensComp(const Bcd a) {
-/+	foreach(Digit digit; a.digits) {
-		digit = 9 - digit;
-	}
-	a = simpleAdd(a, ONE);
-	return a;+/
-
-	Bcd x = Bcd(0, a.numDigits);
-	foreach (int i, digit; a.digits) {
-		x[i] = 9 - digit;
-	}
-	return simpleAdd(x, ONE);
-}
-
-unittest {
-	write("tensComp...");
-	Bcd a, b, c;
-	a = 123456;
-	b = tensComp(a);
-//	writeln("a = ", a);
-//	writeln("b = ", b);
-	c = 876544;
-	assert(b == c);
-	a = Bcd(0, 4);
-	b = tensComp(a);
-	c = 10000;
-	assert(b == c);
-	a = Bcd(1, 4);
-	b = tensComp(a);
-	c = 9999;
-	assert(b == c);
-	a = 9999;
-	b = tensComp(a);
-	c = 1;
-	assert(b == c);
-	a = 10000;
-	b = tensComp(a);
-	c = 90000;
-	assert(b == c);
-	a = 1;
-	b = tensComp(a);
-	c = 9;
-//	writeln("a = ", a);
-//	writeln("b = ", b);
-	assert(b == c);
-	writeln("passed");
-}
-
-// TODO: there are lots of ways to speed this up.
-public Bcd multiply(const Bcd a, const Bcd b) {
-	Bcd n, m;
-	Bcd p = Bcd(0, a.numDigits + b.numDigits);
-	if (a.numDigits > b.numDigits) {
-		n = canonical(a);
-		m = canonical(b);	
-	}
-	else {
-		n = canonical(b);
-		m = canonical(a);
-	}
-	foreach(uint i, Digit d; m.digits) {
-		if (d == 0) continue;
-//        writeln("mul(n, m[i]) = ", mul(n, m[i]));
-//		writeln("pow10(mul(n, m[i]), i) = ", pow10(mul(n, m[i]), i));
-		p = simpleAdd(p, pow10(mul(n, m[i]), i)); 
-	}
-	p.sign = a.sign ^ b.sign;
-	return p;	
-}
-
-unittest {
-	write("mul...");
-	Bcd a, b, p;
-	a = 2105, b = 301;
-	p = multiply(a, b);
-	assert(p == Bcd(633605));
-	b = 800, a = 23958233;
-	p = multiply(a, b);
-	assert(p == Bcd("19166586400"));
-	b = 5830, a = 23958233;
-	p = multiply(a, b);
-	assert(p == Bcd("139676498390"));
-	writeln("passed");
-}
-
-private Bcd mul(const Bcd a, Digit m) {
-	Bcd p = Bcd(0, a.numDigits+1);
-	Digit c = 0;
-	int i = 0;
-	foreach (Digit d; a.digits) {
-		p[i] = mul(m, d, c);
-		i++;
-	}
-	if (c) p[i] = c;
-	return p;
-}
-
-unittest {
-	write("mul...");
-	Bcd a, p;
-	Digit m;
-	a = 2105, m = 3;
-	p = mul(a, m);
-	assert(p == Bcd(6315));
-	writeln("passed");
-}
-
-private Digit mul(Digit a, Digit b, ref Digit c) {
-	Digit p = a * b + c;
-	c = p / 10;
-	return p % 10;
-}
-
-unittest {
-	write("mul...");
-	Digit a, b, c, d;
-	a = 2, b = 3, c = 0;
-	d = mul(a,b,c);
-	assert(d == 6);
-	assert(c == 0);
-	a = 9, b = 8, c = 0;
-	d = mul(a,b,c);
-	assert(d == 2);
-	assert(c == 7);
-	writeln("passed");
-}
-
-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 = canonical(abs(b));
-	r = canonical(abs(a));
-	Bcd q;
-	Bcd p = d;
-	Bcd m;
-	
-	// shift the divisor
-	do {
-		m = p;
-		p <<= 1;
-	} while (p <= r && p > m);
-	
-	while (m >= d) {
-		q <<= 1;
-		// subtract repeatedly
-		while (m <= r) {
-			r -= m;
-			q++;
-		}
-		m >>= 1;
-	}
-	
-	// adjust the sign
-	r.sign = a.sign;
-	q.sign = a.sign != b.sign;
-	return q;
-}
-
-unittest {
-	write("divide...");
-	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);
-	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");
-}
-
-
-public Bcd truncate(const Bcd a, int n) {
-	return truncate(a, n, Bcd());
-}
-
-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 = canonical(a);
-		return ZERO.dup;
-	}
-	if (n >= a.numDigits) {
-		r = ZERO.dup;
-		return canonical(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 pow10(const Bcd a, uint n) {
-	Bcd b = canonical(a);
-	if (n == 0 || b == 0) return b;
-	Digit[] zeros = new Digit[n];
-	b.digits = zeros ~ b.digits;
-	return b;
-}
-
-public Bcd pow10(uint n) {
-	return pow10(ONE, n);
-}
-
-unittest {
-	write("pow10...");
-	Bcd a, b;
-	a = 21345;
-	a = pow10(a, 12);
-	assert(a == Bcd("21345000000000000"));
-	a = pow10(a, 0);
-	assert(a == "21345000000000000"); 
-	a = pow10(9);
-	assert(a == Bcd("1000000000"));
-	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
-		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) {	// shiftFixed left
-		b.digits[0..$-n] = a.digits[n..$];
-	}
-	else {			// shiftFixed right
-		n = -n;
-		b.digits[n..$] = a.digits[0..$-n];
-	}
-	return b;
-}
-
-unittest {
-	write("shiftFixed...");
-	Bcd a, b;
-	a = 1234;
-	b = shiftFixed(a, 1);
-	assert(b.toString == "0123");
-	b = shiftFixed(a, 2);
-	assert(b.toString == "0012");
-	b = shiftFixed(a, -1);
-	assert(b.toString == "2340");
-	b = shiftFixed(a, 0);
-	assert(b.toString == "1234");
-	b = shiftFixed(a, 12);
-	assert(b.toString == "0000");
-	b = shiftFixed(a, -4);
-	assert(b.toString == "0000");
-	writeln("passed");
-}
-
-public Bcd rotate(const Bcd a, int n) {
-	if (n == 0) return a.dup;
-	Bcd b = Bcd(0, a.numDigits);
-	if (std.math.abs(n) >= a.numDigits) {
-		bool sign = n < 0;
-		n = std.math.abs(n) % a.numDigits;
-		if (sign) n = -n;
-	}
-	if (n > 0) {	// rotate left
-		b.digits[0..$-n] = a.digits[n..$];
-		b.digits[$-n..$] = a.digits[0..n];
-	}
-	else {			// rotate right
-		n = -n;
-		b.digits[n..$] = a.digits[0..$-n];
-		b.digits[0..n] = a.digits[$-n..$];
-	}
-	return b;
-}
-
-unittest {
-	write("rotate...");
-	Bcd a, b;
-	a = 1234;
-	b = rotate(a, 1);
-	assert(b.toString == "4123");
-	b = rotate(a, 2);
-	assert(b.toString == "3412");
-	b = rotate(a, -1);
-	assert(b.toString == "2341");
-	b = rotate(a, 0);
-	assert(b.toString == "1234");
-	b = rotate(a, 12);
-	assert(b.toString == "1234");
-	b = rotate(a, -4);
-	assert(b.toString == "1234");
-	writeln("passed");
-}
-
-/**
- * Rounds the specified integer to the specified number of digits.
- * The rounding mode governs the method of rounding.
- */
-public Bcd round(const Bcd a, int n, Rounding mode) {
-	Bcd r;
-	Bcd b = truncate(a, n, r);
-	return round(b, r, mode);
-//	return b;
-}
-
-/**
- * Rounds the (truncated) integer based on its remainder and the rounding
- * mode.
- */
-public Bcd round(const Bcd a, const Bcd r, const Rounding mode) {
-	Bcd b = canonical(a);
-	ubyte rfd = r.firstDigit;
-	switch (mode) {
-		case Rounding.DOWN:
-			return b;
-
-		case Rounding.HALF_UP:
-			if (rfd >= 5) b++;
-			return b;
-
-		case Rounding.HALF_EVEN:
-			if (rfd < 5) return b;
-			if (rfd > 5) return ++b;
-            Bcd p = r.dup;
-			stripr(p);
-			if (p.numDigits > 1) return ++b;
-			// to reach this point the remainder must be exactly 5
-			// if odd, increment
-			if (b.lastDigit & 1 != 0) b++;
-			return b;
-			
-		case Rounding.CEILING:
-			if (!b.isSigned && !r.isZero) b++;
-			return b;
-			
-		case Rounding.FLOOR:
-			if (b.isSigned && !r.isZero) b++;
-			return b;
-			
-		case Rounding.HALF_DOWN:
-			if (rfd < 5) return b;
-			if (rfd > 5) return ++b;
-            Bcd p = r.dup;
-			stripr(p);
-			if (p.numDigits > 1) return ++b;
-			// to reach this point the remainder must be exactly 5
-			return b;
-			
-		case Rounding.UP:
-			if (!r.isZero) b++;
-			return b;
-	}
-	return b;
-}
-
-unittest {
-	write("rounding....");
-	Bcd a, b;
-	a = 12345;
-	b = round(a, 4, Rounding.DOWN);
-	assert(b == 1234);
-	b = round(a, 4, Rounding.HALF_UP);
-	assert(b == 1235);
-	b = round(a, 4, Rounding.CEILING);
-	assert(b == 1235);
-	b = round(a, 4, Rounding.HALF_EVEN);
-	assert(b == 1234);
-	b = round(a, 4, Rounding.FLOOR);
-	assert(b == 1234);
-	b = round(a, 4, Rounding.HALF_DOWN);
-	assert(b == 1234);
-	b = round(a, 4, Rounding.UP);
-	assert(b == 1235);
-	writeln("passed");
-}
-
-
-//==========================================
-
-public void main() {
-	writeln();
-	writeln("If you got this far all the unit tests were successful.");
-	writeln();
-	writeln("      Congratulations!");
-	Bcd bcd;
-	writeln("bcd = ", format(bcd));
-	bcd = parse("12");
-	writeln("bcd = ", format(bcd));
-	bcd = parse("012");
-	writeln("bcd = ", format(bcd));
-	bcd = parse("-012");
-	writeln("bcd = ", format(bcd));
-	bcd = parse("+012");
-	writeln("bcd = ", format(bcd));
-	bcd = parse("-0");
-	writeln("bcd = ", format(bcd));
-	bcd = parse("012_345_678");
-	writeln("bcd = ", format(bcd));
-
-/+	
-	writeln("OK!");+/
-}
-
-
-