comparison src/decimal/bcd.d @ 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
comparison
equal deleted inserted replaced
5:c021ed211f89 6:14badf9104b9
30 * DEALINGS IN THE SOFTWARE. 30 * DEALINGS IN THE SOFTWARE.
31 **/ 31 **/
32 32
33 module decimal.bcd; 33 module decimal.bcd;
34 34
35 //import decimal.context: RoundingMode;
35 import std.algorithm: max; 36 import std.algorithm: max;
36 import std.conv: ConvError; 37 import std.conv: ConvError;
37 import std.math; 38 import std.math;
38 import std.stdio: write, writeln; 39 import std.stdio: write, writeln;
39 import std.string: strip; 40 import std.string: strip;
41 alias ubyte Digit; 42 alias ubyte Digit;
42 43
43 public immutable Bcd ZERO = { digits:[0] }; 44 public immutable Bcd ZERO = { digits:[0] };
44 public immutable Bcd ONE = { digits:[1] }; 45 public immutable Bcd ONE = { digits:[1] };
45 public immutable Bcd NEG_ONE = { sign:true, digits:[1] }; 46 public immutable Bcd NEG_ONE = { sign:true, digits:[1] };
47
48 /**
49 * Enumeration of available rounding modes.
50 */
51 public enum Rounding {
52 HALF_EVEN,
53 HALF_DOWN,
54 HALF_UP,
55 DOWN,
56 UP,
57 FLOOR,
58 CEILING,
59 }
46 60
47 /** 61 /**
48 * Provides BCD-encoded integral values of arbitrary length. 62 * Provides BCD-encoded integral values of arbitrary length.
49 * 63 *
50 * Advantages of BCD: 64 * Advantages of BCD:
203 */ 217 */
204 void setNumDigits(uint n) { 218 void setNumDigits(uint n) {
205 digits.length = n; 219 digits.length = n;
206 } 220 }
207 221
222 unittest {
223 write("setWidth...");
224 Bcd a;
225 a = 1234567;
226 a.setNumDigits(5);
227 writeln("a = ", a);
228 assert(a == Bcd(34567));
229 a.setNumDigits(9);
230 writeln("a = ", a);
231 assert(a.toString == "000034567");
232 writeln("passed");
233 }
234
208 /** 235 /**
209 * Returns the first digit of this BCD integer. If the 236 * Returns the first digit of this BCD integer. If the
210 * integer has leading zeros this function will return 237 * integer has leading zeros this function will return
211 * zero, but the value of the number is not necessarily zero. 238 * zero, but the value of the number is not necessarily zero.
212 */ 239 */
430 const Bcd opNot() { 457 const Bcd opNot() {
431 return not(this); 458 return not(this);
432 } 459 }
433 460
434 Bcd opPostInc() { 461 Bcd opPostInc() {
435 return this + ONE; 462 this = this + ONE;
463 return this;
436 } 464 }
437 465
438 Bcd opPostDec() { 466 Bcd opPostDec() {
439 return this - ONE; 467 this = this - ONE;
468 return this;
469 }
470
471 const Bcd opShl(int n) {
472 return shift(this, n);
473 }
474
475 Bcd opShlAssign(int n) {
476 this = this << n;
477 return this;
478 }
479
480 const Bcd opShr(int n) {
481 return shift(this, -n);
482 }
483
484 Bcd opShrAssign(int n) {
485 this = this >> n;
486 return this;
440 } 487 }
441 488
442 //-------------------------------- 489 //--------------------------------
443 // binary operators 490 // binary operators
444 //-------------------------------- 491 //--------------------------------
827 874
828 private Digit xor(const Digit a, const Digit b) { 875 private Digit xor(const Digit a, const Digit b) {
829 return (a == 0 && b != 0) || (a != 0 && b == 0); 876 return (a == 0 && b != 0) || (a != 0 && b == 0);
830 } 877 }
831 878
879 // TODO: watch the leading zeros
832 public Bcd add(const Bcd x, const Bcd y) { 880 public Bcd add(const Bcd x, const Bcd y) {
833 Bcd a = x.dup; 881 Bcd a = x.dup;
834 Bcd b = y.dup; 882 Bcd b = y.dup;
835 Bcd sum; 883 Bcd sum;
836 if (a.sign == b.sign) { 884 if (a.sign == b.sign) {
860 sum = tensComp(sum); 908 sum = tensComp(sum);
861 sum = stripLeadingZeros(sum); 909 sum = stripLeadingZeros(sum);
862 } 910 }
863 sum.sign = sign; 911 sum.sign = sign;
864 } 912 }
865 return sum; 913 return stripLeadingZeros(sum);
866 } 914 }
867 915
868 unittest { 916 unittest {
869 write("add...."); 917 write("add....");
870 Bcd a, b; 918 Bcd a, b;
1078 assert(d == 2); 1126 assert(d == 2);
1079 assert(c == 7); 1127 assert(c == 7);
1080 writeln("passed"); 1128 writeln("passed");
1081 } 1129 }
1082 1130
1131 public Bcd truncate(const Bcd a, int n) {
1132 /+ if (n <= 0) return ZERO.dup;
1133 if (n >= a.numDigits) return a.dup;
1134 Bcd b;
1135 b.digits = a.digits[$-n..$].dup;
1136 b.sign = a.sign;
1137 return b;+/
1138 Bcd dummy;
1139 return truncate(a, n, dummy);
1140 }
1141
1142 unittest {
1143 write("truncate....");
1144 Bcd a;
1145 a = 1234567;
1146 assert(truncate(a,3) == 123);
1147 a = 10256;
1148 assert(truncate(a,5) == 10256);
1149 a = 8500;
1150 assert(truncate(a,1) == 8);
1151 a = -8500;
1152 assert(truncate(a,1) == -8);
1153 a = -8500;
1154 assert(truncate(a,-1) == 0);
1155 writeln("passed");
1156 }
1157
1158 /**
1159 * Truncate to the specified number of digits
1160 */
1161 public Bcd truncate(const Bcd a, int n, out Bcd r) {
1162 if (n <= 0) {
1163 r = stripLeadingZeros(a);
1164 return ZERO.dup;
1165 }
1166 if (n >= a.numDigits) {
1167 r = ZERO.dup;
1168 return stripLeadingZeros(a);
1169 }
1170 Bcd b;
1171 b.digits = a.digits[$-n..$].dup;
1172 b.sign = a.sign;
1173 r.digits = a.digits[0..$-n].dup;
1174 return b;
1175 }
1176
1177 unittest {
1178 write("truncRem...");
1179 Bcd a;
1180 Bcd r;
1181 a = 1234567;
1182 assert(truncate(a, 3, r) == 123);
1183 assert(r == 4567);
1184 a = 10256;
1185 assert(truncate(a,5,r) == 10256);
1186 assert(r == 0);
1187 a = 8500;
1188 assert(truncate(a,1,r) == 8);
1189 assert(r == 500);
1190 a = -8500;
1191 assert(truncate(a,1,r) == -8);
1192 assert(r == 500);
1193 a = -8500;
1194 // writeln("truncate(a, 6, r) = ", truncate(a, 6, r));
1195 // writeln("r = ", r);
1196 assert(truncate(a,6,r) == -8500);
1197 assert(r == 0);
1198 writeln("passed");
1199 }
1200
1201 public Bcd pad(Bcd a, int n) {
1202 if (n <= a.numDigits) return a.dup;
1203 return Bcd(a,n);
1204 }
1205
1206 unittest {
1207 write("pad.........");
1208 Bcd a;
1209 a = 1234567;
1210 assert(pad(a,3) == 1234567);
1211 a = 10256;
1212 // writeln("pad(a,9) = ", pad(a,9));
1213 assert(pad(a,9).toString == "000010256");
1214 a = 8500;
1215 assert(pad(a,6).toString == "008500");
1216 a = -8500;
1217 assert(pad(a,6).toString == "-008500");
1218 writeln("passed");
1219 }
1220 public Bcd divide(const Bcd a, const Bcd b, out Bcd remainder) {
1221 Bcd quotient;
1222 Bcd dividend = stripLeadingZeros(a);
1223 // writeln("dividend = ", dividend);
1224 Bcd divisor = stripLeadingZeros(b);
1225 // writeln("divisor = ", divisor);
1226 if (divisor == ZERO) throw new Exception("Divide by zero");
1227 remainder = dividend;
1228 writeln("remainder = ", remainder);
1229 Bcd next = divisor;
1230 // writeln("next = ", next);
1231 Bcd multiple;
1232
1233 do {
1234 multiple = next;
1235 // writeln("multiple = ", multiple);
1236 next <<= 1;
1237 // writeln("next = ", next);
1238 } while (next <= remainder && next > multiple);
1239
1240 while (multiple >= divisor) {
1241 quotient <<= 1;
1242 // writeln("quotient = ", quotient);
1243 while (multiple <= remainder) {
1244 remainder -= multiple;
1245 writeln("remainder = ", remainder);
1246 quotient++;
1247 // writeln("quotient = ", quotient);
1248 }
1249 multiple >>= 1;
1250 // writeln("multiple = ", multiple);
1251 }
1252 return quotient;
1253 }
1254
1255 unittest {
1256 write("divide...");
1257 writeln();
1258 Bcd a, b, q, r;
1259 a = 144;
1260 b = 12;
1261 q = divide(a, b, r);
1262 assert(q == 12);
1263 assert(r == 0);
1264 a = 144;
1265 b = 14;
1266 q = divide(a, b, r);
1267 assert(q == 10);
1268 assert(r == 4);
1269 a = 142351;
1270 b = 12;
1271 q = divide(a, b, r);
1272 writeln("q = ", q);
1273 writeln("r = ", r);
1274 assert(q == 11862);
1275 assert(r == 7);
1276 a = 2;
1277 b = 12;
1278 q = divide(a, b, r);
1279 assert(q == 0);
1280 assert(r == 2);
1281 writeln("passed");
1282 }
1283
1284
1083 public Bcd pow10(const Bcd a, uint n) { 1285 public Bcd pow10(const Bcd a, uint n) {
1084 Bcd b = a.dup; 1286 Bcd b = stripLeadingZeros(a);
1085 if (n == 0) return b; 1287 if (n == 0 || b == 0) return b;
1086 Digit[] zeros = new Digit[n]; 1288 Digit[] zeros = new Digit[n];
1087 b.digits = zeros ~ b.digits; 1289 b.digits = zeros ~ b.digits;
1088 return b; 1290 return b;
1089 } 1291 }
1090 1292
1104 assert(a == Bcd("1000000000")); 1306 assert(a == Bcd("1000000000"));
1105 writeln("passed"); 1307 writeln("passed");
1106 } 1308 }
1107 1309
1108 public Bcd shift(const Bcd a, int n) { 1310 public Bcd shift(const Bcd a, int n) {
1311 if (n == 0) return stripLeadingZeros(a);
1312 if (n > 0) { // shift left
1313 return pow10(a, n);
1314 }
1315 else { // shift right
1316 if (-n >= a.numDigits) return ZERO.dup;
1317 return truncate(a, a.numDigits + n);
1318 }
1319 }
1320
1321 unittest {
1322 write("shift.......");
1323 Bcd a, b;
1324 a = 1234;
1325 b = shift(a, 1);
1326 assert(b.toString == "12340");
1327 b = shift(a, 2);
1328 assert(b.toString == "123400");
1329 b = shift(a, -1);
1330 // writeln("b = ", b);
1331 assert(b.toString == "123");
1332 b = shift(a, 0);
1333 assert(b.toString == "1234");
1334 b = shift(a, -12);
1335 /+ writeln("b = ", b);+/
1336 assert(b.toString == "0");
1337 b = shift(a, -4);
1338 assert(b.toString == "0");
1339 writeln("passed");
1340 }
1341
1342 public Bcd shiftFixed(const Bcd a, int n) {
1109 if (n == 0) return a.dup; 1343 if (n == 0) return a.dup;
1110 Bcd b = Bcd(0, a.numDigits); 1344 Bcd b = Bcd(0, a.numDigits);
1111 if (std.math.abs(n) >= a.numDigits) return b; 1345 if (std.math.abs(n) >= a.numDigits) return b;
1112 if (n > 0) { // shift left 1346 if (n > 0) { // shiftFixed left
1113 b.digits[0..$-n] = a.digits[n..$]; 1347 b.digits[0..$-n] = a.digits[n..$];
1114 } 1348 }
1115 else { // shift right 1349 else { // shiftFixed right
1116 n = -n; 1350 n = -n;
1117 b.digits[n..$] = a.digits[0..$-n]; 1351 b.digits[n..$] = a.digits[0..$-n];
1118 } 1352 }
1119 return b; 1353 return b;
1120 } 1354 }
1121 1355
1122 unittest { 1356 unittest {
1123 write("shift..."); 1357 write("shiftFixed...");
1124 Bcd a, b; 1358 Bcd a, b;
1125 a = 1234; 1359 a = 1234;
1126 b = shift(a, 1); 1360 b = shiftFixed(a, 1);
1127 assert(b.toString == "0123"); 1361 assert(b.toString == "0123");
1128 b = shift(a, 2); 1362 b = shiftFixed(a, 2);
1129 assert(b.toString == "0012"); 1363 assert(b.toString == "0012");
1130 b = shift(a, -1); 1364 b = shiftFixed(a, -1);
1131 assert(b.toString == "2340"); 1365 assert(b.toString == "2340");
1132 b = shift(a, 0); 1366 b = shiftFixed(a, 0);
1133 assert(b.toString == "1234"); 1367 assert(b.toString == "1234");
1134 b = shift(a, 12); 1368 b = shiftFixed(a, 12);
1135 assert(b.toString == "0000"); 1369 assert(b.toString == "0000");
1136 b = shift(a, -4); 1370 b = shiftFixed(a, -4);
1137 assert(b.toString == "0000"); 1371 assert(b.toString == "0000");
1138 writeln("passed"); 1372 writeln("passed");
1139 } 1373 }
1140 1374
1141 public Bcd rotate(const Bcd a, int n) { 1375 public Bcd rotate(const Bcd a, int n) {