comparison src/decimal/bcd.d @ 9:48d564218e05

Added rounding, additional unit tests, strip leading and trailing zeros.
author Paul (paul.d.anderson@comcast.net)
date Wed, 24 Mar 2010 22:21:38 -0700
parents c991b9fde45c
children f925fe996255
comparison
equal deleted inserted replaced
8:c991b9fde45c 9:48d564218e05
216 * padding or truncating if necessary. 216 * padding or truncating if necessary.
217 * If truncating, first leading zeros are stripped away, then 217 * If truncating, first leading zeros are stripped away, then
218 * the remainder is clipped. 218 * the remainder is clipped.
219 */ 219 */
220 void setNumDigits(uint n) { 220 void setNumDigits(uint n) {
221 this = stripLeadingZeros(this); 221 stripl(this);
222 if (n > digits.length) { 222 if (n > digits.length) {
223 digits.length = n; 223 digits.length = n;
224 } 224 }
225 else { 225 else {
226 this = truncate(this, n); 226 this = truncate(this, n);
341 /** 341 /**
342 * Returns true if the internal representation of 342 * Returns true if the internal representation of
343 * this BCD integer has leading zeros. 343 * this BCD integer has leading zeros.
344 */ 344 */
345 const bool hasLeadingZeros() { 345 const bool hasLeadingZeros() {
346 return numDigits > 0 && firstDigit == 0; 346 return numDigits > 1 && firstDigit == 0;
347 }
348
349 unittest {
350 write("hasLeadingZeros...");
351 assert(!ZERO.hasLeadingZeros);
352 Bcd b = Bcd(0);
353 assert(!b.hasLeadingZeros);
354 b = "-00000001";
355 assert(b.hasLeadingZeros);
356 b = "-00000000";
357 assert(b.hasLeadingZeros);
358 writeln("passed");
347 } 359 }
348 360
349 /** 361 /**
350 * Returns true if the value of this BCD integer is zero. 362 * Returns true if the value of this BCD integer is zero.
351 * Ignores and leading zeros and the sign of the number. 363 * Ignores leading zeros and sign.
352 */ 364 */
353 const bool isZero() { 365 const bool isZero() {
354 Bcd temp = stripLeadingZeros(this); 366 Bcd b = canonical(this);
355 if (temp.numDigits > 1) return false; 367 if (b.numDigits > 1) return false;
356 return temp.lastDigit == 0; 368 return b.lastDigit == 0;
369 }
370
371 unittest {
372 write("isZero.........");
373 assert(ZERO.isZero);
374 Bcd b = Bcd(0);
375 assert(b.isZero);
376 b = "-00000001";
377 assert(!b.isZero);
378 b = "-00000000";
379 assert(b.isZero);
380 writeln("passed");
357 } 381 }
358 382
359 //-------------------------------- 383 //--------------------------------
360 // Assignment operators. 384 // Assignment operators.
361 //-------------------------------- 385 //--------------------------------
381 * Converts the integer argument into a BCD integer and assigns it 405 * Converts the integer argument into a BCD integer and assigns it
382 * to this BCD integer. 406 * to this BCD integer.
383 */ 407 */
384 void opAssign(const long n) { 408 void opAssign(const long n) {
385 this = Bcd(n); 409 this = Bcd(n);
386 /+ uint m;
387 if (n < 0) {
388 sign = true;
389 m = std.math.abs(n);
390 }
391 else {
392 sign = false;
393 m = n;
394 }
395 Digit[20] dig;
396 int i = 0;
397 do {
398 uint q = m/10;
399 uint r = m%10;
400 dig[i] = cast(Digit) r;
401 m = q;
402 i++;
403 } while (m > 0);
404 digits = dig[0..i].dup;+/
405 } 410 }
406 411
407 412
408 // index operator 413 // index operator
409 Digit opIndex(uint index) { 414 Digit opIndex(uint index) {
413 // index assign operator 418 // index assign operator
414 void opIndexAssign(Digit value, uint index) { 419 void opIndexAssign(Digit value, uint index) {
415 this.digits[index] = value; 420 this.digits[index] = value;
416 } 421 }
417 422
418 /+ int opApply(int delegate (ref Digit) dg) {
419 int result = 0;
420 for (int i = 0; i < numDigits; i++) {
421 result = dg(digits[i]);
422 if (result) break;
423 }
424 return result;
425 }
426
427 int opApply(int delegate (ref Digit) dg) {
428 int result = 0;
429 for (int i = 0; i < numDigits; i++) {
430 result = dg(digits[i]);
431 if (result) break;
432 }
433 return result;
434 }
435
436 int opApplyReverse(int delegate (ref Digit) dg) {
437 int result = 0;
438 for (int i = 0; i < numDigits; i++) {
439 result = dg(digits[i]);
440 if (result) break;
441 }
442 return result;
443 }+/
444
445 //-------------------------------- 423 //--------------------------------
446 // unary operators 424 // unary operators
447 //-------------------------------- 425 //--------------------------------
448 426
449 const Bcd opPos() { 427 const Bcd opPos() {
450 return this.dup; 428 return this.dup;
451 } 429 }
452 430
453 const Bcd opNeg() { 431 const Bcd opNeg() {
454 Bcd copy = this.dup; 432 return negate(this);
455 copy.sign = !this.sign;
456 return copy;
457 } 433 }
458 434
459 const Bcd opCom() { 435 const Bcd opCom() {
460 return twosComp(this); 436 return twosComp(this);
461 } 437 }
649 const int opCmp(T)(const T that) { 625 const int opCmp(T)(const T that) {
650 return opCmp(Bcd(that)); 626 return opCmp(Bcd(that));
651 } 627 }
652 628
653 const bool opEquals(T:Bcd)(const T that) { 629 const bool opEquals(T:Bcd)(const T that) {
654 Bcd a = stripLeadingZeros(this); 630 Bcd a = canonical(this);
655 Bcd b = stripLeadingZeros(that); 631 Bcd b = canonical(that);
632 // TODO: this is wrong -- signs can differ -0 and + 0
656 if (this.sign != that.sign) return false; 633 if (this.sign != that.sign) return false;
657 if (a.digits.length != b.digits.length) return false; 634 if (a.digits.length != b.digits.length) return false;
658 foreach_reverse(int i, Digit digit; a.digits) { 635 foreach_reverse(int i, Digit digit; a.digits) {
659 if (digit != b.digits[i]) return false; 636 if (digit != b.digits[i]) return false;
660 } 637 }
661 return true; 638 return true;
662 // return compare(this, that) == 0;
663 } 639 }
664 640
665 const bool opEquals(T)(const T that) { 641 const bool opEquals(T)(const T that) {
666 return opEquals(Bcd(that)); 642 return opEquals(Bcd(that));
667 } 643 }
682 writeln("passed"); 658 writeln("passed");
683 } 659 }
684 660
685 } // end struct Bcd 661 } // end struct Bcd
686 662
663
664 public bool isCanonical(const Bcd a) {
665 // no leading zeros
666 if (a.hasLeadingZeros) return false;
667 // not -0
668 if (a.numDigits == 1 && a.firstDigit == 0) return !a.sign;
669 return true;
670 }
671
672 // Strips leading zeros and changes sign if == -0
673 public Bcd canonical(const Bcd a) {
674 Bcd d = a.dup;
675 if (isCanonical(a)) return d;
676 stripl(d);
677 if (d.numDigits == 1 && d.firstDigit == 0) {
678 d.sign = false;
679 }
680 return d;
681 }
682
683 /**
684 * Strips leading zeros from the specified decint.
685 */
686 private void stripl(ref Bcd a) {
687 if (a.hasLeadingZeros) {
688 foreach_reverse(int i, Digit digit; a.digits) {
689 if (i == 0 || digit != 0) {
690 a.digits.length = i+1;
691 break;
692 }
693 }
694 }
695 }
696
697 unittest {
698 write("stripl......");
699 Bcd b = Bcd("+00023");
700 assert(b.toString == "00023");
701 stripl(b);
702 assert(b.toString == "23");
703 b = "-00050432";
704 stripl(b);
705 assert(b.toString == "-50432");
706 b = "-000";
707 stripl(b);
708 assert(b.toString == "-0");
709 writeln("passed");
710 }
711
712 /**
713 * Strips trailing zeros from the specified decint.
714 */
715 private void stripr(ref Bcd a) {
716 int len = a.digits.length;
717 foreach(int i, Digit digit; a.digits) {
718 if (i == len-1 || digit != 0) {
719 a.digits = a.digits[i..$];
720 break;
721 }
722 }
723 }
724
725 unittest {
726 write("stripl......");
727 Bcd b;
728 b = 23;
729 stripr(b);
730 assert(b == 23);
731 b = "-5000";
732 stripr(b);
733 assert(b.toString == "-5");
734 b = "-000";
735 stripr(b);
736 assert(b.toString == "-0");
737 writeln("passed");
738 }
739
687 //public string format(const Bcd bcd, bool showPlus = false, bool showLeadingZeros = false) { 740 //public string format(const Bcd bcd, bool showPlus = false, bool showLeadingZeros = false) {
688 public string format(const Bcd bcd) { 741 public string format(const Bcd bcd) {
689 int len = bcd.digits.length; 742 int len = bcd.digits.length;
690 if (bcd.isSigned) len++; 743 if (bcd.isSigned) len++;
691 // if (bcd.isSigned || bcd.hasLeadingZeros) len++; 744 // if (bcd.isSigned || bcd.hasLeadingZeros) len++;
748 bcd.digits.length = index; 801 bcd.digits.length = index;
749 foreach(int i, char ch; str2) { 802 foreach(int i, char ch; str2) {
750 bcd.digits[i] = cast(Digit)(ch - '0'); 803 bcd.digits[i] = cast(Digit)(ch - '0');
751 } 804 }
752 805
753 if (!lz) return stripLeadingZeros(bcd); 806 if (!lz) return canonical(bcd);
754 return bcd; 807 return bcd;
755 } 808 }
756 809
757 private bool isDigit(const char ch) { 810 private bool isDigit(const char ch) {
758 return (ch >= '0' && ch <= '9'); 811 return (ch >= '0' && ch <= '9');
759 } 812 }
760 813
761 public Bcd negate(const Bcd a) { 814 public Bcd negate(const Bcd a) {
762 return -a; 815 Bcd b = a.dup;
816 b.sign = !a.sign;
817 return b;
763 } 818 }
764 819
765 public Bcd abs(const Bcd a) { 820 public Bcd abs(const Bcd a) {
766 return a.isSigned ? -a: +a; 821 return a.isSigned ? -a: +a;
767 } 822 }
768 823
769 public int compare(const Bcd m, const Bcd n) { 824 public int compare(const Bcd m, const Bcd n) {
770 Bcd a = stripLeadingZeros(m); 825 Bcd a = canonical(m);
771 Bcd b = stripLeadingZeros(n); 826 Bcd b = canonical(n);
772 if (!a.isSigned && b.isSigned) return 1; 827 if (!a.isSigned && b.isSigned) return 1;
773 if (a.isSigned && !b.isSigned) return -1; 828 if (a.isSigned && !b.isSigned) return -1;
774 if (a.digits.length > b.digits.length) return 1; 829 if (a.digits.length > b.digits.length) return 1;
775 if (a.digits.length < b.digits.length) return -1; 830 if (a.digits.length < b.digits.length) return -1;
776 foreach_reverse(int i, Digit digit; a.digits) { 831 foreach_reverse(int i, Digit digit; a.digits) {
778 if (digit < b.digits[i]) return -1; 833 if (digit < b.digits[i]) return -1;
779 } 834 }
780 return 0; 835 return 0;
781 } 836 }
782 837
783 // TODO: does this need a const and a dup?
784 // should it be public?? private would be okay
785 public Bcd stripLeadingZeros(const Bcd a) {
786 Bcd d = a.dup;
787 if (!a.hasLeadingZeros) return d;
788 int len = a.numDigits;
789 int i = 0;
790 while(i < len-1 && a.getDigit(i) == 0) {
791 i++;
792 }
793 d.digits.length = (len-i); // - 1);
794 if (d.numDigits == 1 && d.firstDigit == 0) {
795 d.sign = false;
796 }
797 return d;
798 }
799
800 unittest { 838 unittest {
801 write("strip..."); 839 write("strip...");
802 Bcd bcd; 840 Bcd bcd;
803 bcd = "+00123"; 841 bcd = "+00123";
804 assert(bcd.toString == "00123"); 842 assert(bcd.toString == "00123");
805 bcd = stripLeadingZeros(bcd); 843 bcd = canonical(bcd);
806 // writeln("bcd = ", bcd); 844 // writeln("bcd = ", bcd);
807 assert(bcd.toString == "123"); 845 assert(bcd.toString == "123");
808 bcd = "+000"; 846 bcd = "+000";
809 // writeln("bcd = ", bcd); 847 // writeln("bcd = ", bcd);
810 assert(bcd.toString == "000"); 848 assert(bcd.toString == "000");
811 bcd = stripLeadingZeros(bcd); 849 bcd = canonical(bcd);
812 // writeln("bcd = ", bcd); 850 // writeln("bcd = ", bcd);
813 writeln("passed"); 851 writeln("passed");
814 } 852 }
815 853
816 public bool sameLength(const Bcd a, const Bcd b) { 854 public bool sameLength(const Bcd a, const Bcd b) {
939 Bcd a = x.dup; 977 Bcd a = x.dup;
940 Bcd b = y.dup; 978 Bcd b = y.dup;
941 Bcd sum; 979 Bcd sum;
942 if (a.sign == b.sign) { 980 if (a.sign == b.sign) {
943 sum = simpleAdd(a, b); 981 sum = simpleAdd(a, b);
944 sum = stripLeadingZeros(sum); 982 stripl(sum);
945 sum.sign = a.sign; 983 sum.sign = a.sign;
946 return sum; 984 return sum;
947 } 985 }
948 else { // signs differ 986 else { // signs differ
949 bool sign; 987 bool sign;
962 if (sum.firstDigit == 1) { 1000 if (sum.firstDigit == 1) {
963 sum.digits = sum.digits[0..$-1]; 1001 sum.digits = sum.digits[0..$-1];
964 } 1002 }
965 else { 1003 else {
966 sum = tensComp(sum); 1004 sum = tensComp(sum);
967 sum = stripLeadingZeros(sum);
968 } 1005 }
1006 stripl(sum);
969 sum.sign = sign; 1007 sum.sign = sign;
970 } 1008 }
971 return stripLeadingZeros(sum); 1009 return sum;
972 } 1010 }
973 1011
974 unittest { 1012 unittest {
975 write("add...."); 1013 write("add....");
976 Bcd a, b; 1014 Bcd a, b;
1027 } 1065 }
1028 if (carry) { 1066 if (carry) {
1029 sum[i] = 1; 1067 sum[i] = 1;
1030 } 1068 }
1031 else { 1069 else {
1032 sum = stripLeadingZeros(sum); 1070 stripl(sum);
1033 } 1071 }
1034 return sum; 1072 return sum;
1035 } 1073 }
1074
1075 // TODO: need a clipFirst, clipLast method
1036 1076
1037 /** 1077 /**
1038 * Adds two digits and a carry digit. 1078 * Adds two digits and a carry digit.
1039 * Returns the (single-digit) sum and sets or resets the carry digit. 1079 * Returns the (single-digit) sum and sets or resets the carry digit.
1040 **/ 1080 **/
1110 // TODO: there are lots of ways to speed this up. 1150 // TODO: there are lots of ways to speed this up.
1111 public Bcd multiply(const Bcd a, const Bcd b) { 1151 public Bcd multiply(const Bcd a, const Bcd b) {
1112 Bcd n, m; 1152 Bcd n, m;
1113 Bcd p = Bcd(0, a.numDigits + b.numDigits); 1153 Bcd p = Bcd(0, a.numDigits + b.numDigits);
1114 if (a.numDigits > b.numDigits) { 1154 if (a.numDigits > b.numDigits) {
1115 n = stripLeadingZeros(a); 1155 n = canonical(a);
1116 m = stripLeadingZeros(b); 1156 m = canonical(b);
1117 } 1157 }
1118 else { 1158 else {
1119 n = stripLeadingZeros(b); 1159 n = canonical(b);
1120 m = stripLeadingZeros(a); 1160 m = canonical(a);
1121 } 1161 }
1122 foreach(uint i, Digit d; m.digits) { 1162 foreach(uint i, Digit d; m.digits) {
1123 if (d == 0) continue; 1163 if (d == 0) continue;
1124 // writeln("mul(n, m[i]) = ", mul(n, m[i])); 1164 // writeln("mul(n, m[i]) = ", mul(n, m[i]));
1125 // writeln("pow10(mul(n, m[i]), i) = ", pow10(mul(n, m[i]), i)); 1165 // writeln("pow10(mul(n, m[i]), i) = ", pow10(mul(n, m[i]), i));
1184 assert(d == 2); 1224 assert(d == 2);
1185 assert(c == 7); 1225 assert(c == 7);
1186 writeln("passed"); 1226 writeln("passed");
1187 } 1227 }
1188 1228
1189 public Bcd truncate(const Bcd a, int n) {
1190 Bcd dummy;
1191 return truncate(a, n, dummy);
1192 }
1193
1194 unittest {
1195 write("truncate....");
1196 Bcd a;
1197 a = 1234567;
1198 assert(truncate(a,3) == 123);
1199 a = 10256;
1200 assert(truncate(a,5) == 10256);
1201 a = 8500;
1202 assert(truncate(a,1) == 8);
1203 a = -8500;
1204 assert(truncate(a,1) == -8);
1205 a = -8500;
1206 assert(truncate(a,-1) == 0);
1207 writeln("passed");
1208 }
1209
1210 /**
1211 * Truncate to the specified number of digits
1212 */
1213 public Bcd truncate(const Bcd a, int n, out Bcd r) {
1214 if (n <= 0) {
1215 r = stripLeadingZeros(a);
1216 return ZERO.dup;
1217 }
1218 if (n >= a.numDigits) {
1219 r = ZERO.dup;
1220 return stripLeadingZeros(a);
1221 }
1222 Bcd b;
1223 b.digits = a.digits[$-n..$].dup;
1224 b.sign = a.sign;
1225 r.digits = a.digits[0..$-n].dup;
1226 return b;
1227 }
1228
1229 unittest {
1230 write("truncRem...");
1231 Bcd a;
1232 Bcd r;
1233 a = 1234567;
1234 assert(truncate(a, 3, r) == 123);
1235 assert(r == 4567);
1236 a = 10256;
1237 assert(truncate(a,5,r) == 10256);
1238 assert(r == 0);
1239 a = 8500;
1240 assert(truncate(a,1,r) == 8);
1241 assert(r == 500);
1242 a = -8500;
1243 assert(truncate(a,1,r) == -8);
1244 assert(r == 500);
1245 a = -8500;
1246 // writeln("truncate(a, 6, r) = ", truncate(a, 6, r));
1247 // writeln("r = ", r);
1248 assert(truncate(a,6,r) == -8500);
1249 assert(r == 0);
1250 writeln("passed");
1251 }
1252
1253 public Bcd pad(Bcd a, int n) {
1254 if (n <= a.numDigits) return a.dup;
1255 return Bcd(a,n);
1256 }
1257
1258 unittest {
1259 write("pad.........");
1260 Bcd a;
1261 a = 1234567;
1262 assert(pad(a,3) == 1234567);
1263 a = 10256;
1264 // writeln("pad(a,9) = ", pad(a,9));
1265 assert(pad(a,9).toString == "000010256");
1266 a = 8500;
1267 assert(pad(a,6).toString == "008500");
1268 a = -8500;
1269 assert(pad(a,6).toString == "-008500");
1270 writeln("passed");
1271 }
1272 public Bcd divide(const Bcd a, const Bcd b, out Bcd r) { 1229 public Bcd divide(const Bcd a, const Bcd b, out Bcd r) {
1273 1230
1274 if (b == ZERO) throw new Exception("Divide by zero"); 1231 if (b == ZERO) throw new Exception("Divide by zero");
1275 if (a == ZERO) return ZERO.dup; 1232 if (a == ZERO) return ZERO.dup;
1276 1233
1277 Bcd d = stripLeadingZeros(abs(b)); 1234 Bcd d = canonical(abs(b));
1278 r = stripLeadingZeros(abs(a)); 1235 r = canonical(abs(a));
1279 Bcd q; 1236 Bcd q;
1280 Bcd p = d; 1237 Bcd p = d;
1281 Bcd m; 1238 Bcd m;
1282 1239
1283 // shift the divisor 1240 // shift the divisor
1349 assert(r == -1); 1306 assert(r == -1);
1350 writeln("passed"); 1307 writeln("passed");
1351 } 1308 }
1352 1309
1353 1310
1311 public Bcd truncate(const Bcd a, int n) {
1312 Bcd dummy;
1313 return truncate(a, n, dummy);
1314 }
1315
1316 unittest {
1317 write("truncate....");
1318 Bcd a;
1319 a = 1234567;
1320 assert(truncate(a,3) == 123);
1321 a = 10256;
1322 assert(truncate(a,5) == 10256);
1323 a = 8500;
1324 assert(truncate(a,1) == 8);
1325 a = -8500;
1326 assert(truncate(a,1) == -8);
1327 a = -8500;
1328 assert(truncate(a,-1) == 0);
1329 writeln("passed");
1330 }
1331
1332 /**
1333 * Truncate to the specified number of digits
1334 */
1335 public Bcd truncate(const Bcd a, int n, out Bcd r) {
1336 if (n <= 0) {
1337 r = canonical(a);
1338 return ZERO.dup;
1339 }
1340 if (n >= a.numDigits) {
1341 r = ZERO.dup;
1342 return canonical(a);
1343 }
1344 Bcd b;
1345 b.digits = a.digits[$-n..$].dup;
1346 b.sign = a.sign;
1347 r.digits = a.digits[0..$-n].dup;
1348 return b;
1349 }
1350
1351 unittest {
1352 write("truncRem...");
1353 Bcd a;
1354 Bcd r;
1355 a = 1234567;
1356 assert(truncate(a, 3, r) == 123);
1357 assert(r == 4567);
1358 a = 10256;
1359 assert(truncate(a,5,r) == 10256);
1360 assert(r == 0);
1361 a = 8500;
1362 assert(truncate(a,1,r) == 8);
1363 assert(r == 500);
1364 a = -8500;
1365 assert(truncate(a,1,r) == -8);
1366 assert(r == 500);
1367 a = -8500;
1368 // writeln("truncate(a, 6, r) = ", truncate(a, 6, r));
1369 // writeln("r = ", r);
1370 assert(truncate(a,6,r) == -8500);
1371 assert(r == 0);
1372 writeln("passed");
1373 }
1374
1375 public Bcd pad(Bcd a, int n) {
1376 if (n <= a.numDigits) return a.dup;
1377 return Bcd(a,n);
1378 }
1379
1380 unittest {
1381 write("pad.........");
1382 Bcd a;
1383 a = 1234567;
1384 assert(pad(a,3) == 1234567);
1385 a = 10256;
1386 // writeln("pad(a,9) = ", pad(a,9));
1387 assert(pad(a,9).toString == "000010256");
1388 a = 8500;
1389 assert(pad(a,6).toString == "008500");
1390 a = -8500;
1391 assert(pad(a,6).toString == "-008500");
1392 writeln("passed");
1393 }
1394
1354 public Bcd pow10(const Bcd a, uint n) { 1395 public Bcd pow10(const Bcd a, uint n) {
1355 Bcd b = stripLeadingZeros(a); 1396 Bcd b = canonical(a);
1356 if (n == 0 || b == 0) return b; 1397 if (n == 0 || b == 0) return b;
1357 Digit[] zeros = new Digit[n]; 1398 Digit[] zeros = new Digit[n];
1358 b.digits = zeros ~ b.digits; 1399 b.digits = zeros ~ b.digits;
1359 return b; 1400 return b;
1360 } 1401 }
1375 assert(a == Bcd("1000000000")); 1416 assert(a == Bcd("1000000000"));
1376 writeln("passed"); 1417 writeln("passed");
1377 } 1418 }
1378 1419
1379 public Bcd shift(const Bcd a, int n) { 1420 public Bcd shift(const Bcd a, int n) {
1380 if (n == 0) return stripLeadingZeros(a); 1421 if (n == 0) return canonical(a);
1381 if (n > 0) { // shift left 1422 if (n > 0) { // shift left
1382 return pow10(a, n); 1423 return pow10(a, n);
1383 } 1424 }
1384 else { // shift right 1425 else { // shift right
1385 if (-n >= a.numDigits) return ZERO.dup; 1426 if (-n >= a.numDigits) return ZERO.dup;
1482 1523
1483 /** 1524 /**
1484 * Rounds the specified integer to the specified number of digits. 1525 * Rounds the specified integer to the specified number of digits.
1485 * The rounding mode governs the method of rounding. 1526 * The rounding mode governs the method of rounding.
1486 */ 1527 */
1487 public Bcd round(Bcd a, int n, Rounding mode) { 1528 public Bcd round(const Bcd a, int n, Rounding mode) {
1488 Bcd r; 1529 Bcd r;
1489 Bcd b = truncate(a, n, r); 1530 Bcd b = truncate(a, n, r);
1490 return b; 1531 return round(b, r, mode);
1532 // return b;
1491 } 1533 }
1492 1534
1493 /** 1535 /**
1494 * Rounds the (truncated) integer based on its remainder and the rounding 1536 * Rounds the (truncated) integer based on its remainder and the rounding
1495 * mode. 1537 * mode.
1496 */ 1538 */
1497 public Bcd round(Bcd a, Bcd r, Rounding mode) { 1539 public Bcd round(const Bcd a, const Bcd r, const Rounding mode) {
1498 Bcd b = a.dup; 1540 Bcd b = canonical(a);
1541 ubyte rfd = r.firstDigit;
1499 switch (mode) { 1542 switch (mode) {
1500 case Rounding.DOWN: 1543 case Rounding.DOWN:
1501 return b; 1544 return b;
1502 1545
1503 case Rounding.HALF_UP: 1546 case Rounding.HALF_UP:
1504 if (r.firstDigit >= 5) b++; 1547 if (rfd >= 5) b++;
1505 return b; 1548 return b;
1506 1549
1507 case Rounding.HALF_EVEN: 1550 case Rounding.HALF_EVEN:
1508 /+ BigInt test = 5 * pow10(numDigits(remainder,1)-1); 1551 if (rfd < 5) return b;
1509 int result = remainder.opCmp(test); 1552 if (rfd > 5) return ++b;
1510 if (result > 0) { 1553 Bcd p = r.dup;
1511 increment(number.ceff); 1554 stripr(p);
1512 return; 1555 if (p.numDigits > 1) return ++b;
1513 } 1556 // to reach this point the remainder must be exactly 5
1514 if (result < 0) { 1557 // if odd, increment
1515 return; 1558 if (b.lastDigit & 1 != 0) b++;
1516 }
1517 // if last digit is odd...
1518 if (lastDigit(number.ceff) & 1 == 1) {
1519 increment(number.ceff);
1520 }+/
1521 return b; 1559 return b;
1522 1560
1523 case Rounding.CEILING: 1561 case Rounding.CEILING:
1524 if (!b.isSigned && !r.isZero) b++; 1562 if (!b.isSigned && !r.isZero) b++;
1525 return b; 1563 return b;
1526 1564
1527 case Rounding.FLOOR: 1565 case Rounding.FLOOR:
1528 if (b.isSigned && !r.isZero) b++; 1566 if (b.isSigned && !r.isZero) b++;
1529 return b; 1567 return b;
1530 1568
1531 // TODO: is this one right? what about 55...
1532 case Rounding.HALF_DOWN: 1569 case Rounding.HALF_DOWN:
1533 if (r.firstDigit > 5) b++; 1570 if (rfd < 5) return b;
1571 if (rfd > 5) return ++b;
1572 Bcd p = r.dup;
1573 stripr(p);
1574 if (p.numDigits > 1) return ++b;
1575 // to reach this point the remainder must be exactly 5
1534 return b; 1576 return b;
1535 1577
1536 case Rounding.UP: 1578 case Rounding.UP:
1537 if (!r.isZero) b++; 1579 if (!r.isZero) b++;
1538 return b; 1580 return b;
1539 } 1581 }
1540 return b; 1582 return b;
1541 } 1583 }
1542 1584
1543 unittest { 1585 unittest {
1544 write("rounding......."); 1586 write("rounding....");
1587 Bcd a, b;
1588 a = 12345;
1589 b = round(a, 4, Rounding.DOWN);
1590 assert(b == 1234);
1591 b = round(a, 4, Rounding.HALF_UP);
1592 assert(b == 1235);
1593 b = round(a, 4, Rounding.CEILING);
1594 assert(b == 1235);
1595 b = round(a, 4, Rounding.HALF_EVEN);
1596 assert(b == 1234);
1597 b = round(a, 4, Rounding.FLOOR);
1598 assert(b == 1234);
1599 b = round(a, 4, Rounding.HALF_DOWN);
1600 assert(b == 1234);
1601 b = round(a, 4, Rounding.UP);
1602 assert(b == 1235);
1545 writeln("passed"); 1603 writeln("passed");
1546 } 1604 }
1547 1605
1548 1606
1549 //========================================== 1607 //==========================================