# HG changeset patch # User Paul (paul.d.anderson@comcast.net) # Date 1269572700 25200 # Node ID f925fe996255745e72323467115cd028d127f377 # Parent 48d564218e05853593f0a74c91dbc8a8c5cf1fd6 added cast, clip, power diff -r 48d564218e05 -r f925fe996255 src/decimal/bcd.d --- 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