1 13 14 package mondrian.util; 15 import mondrian.olap.Util; 16 17 import java.io.PrintWriter ; 18 import java.math.BigDecimal ; 19 import java.math.BigInteger ; 20 import java.text.*; 21 import java.util.*; 22 23 63 public class Format { 64 private String formatString; 65 private BasicFormat format; 66 private FormatLocale locale; 67 private static final FieldPosition dummyFieldPos = createDummyFieldPos(); 68 69 73 public static final int CacheLimit = 1000; 74 75 80 private static FieldPosition createDummyFieldPos() { 81 final FieldPosition[] pos = {null}; 82 new DecimalFormat() { 83 public StringBuffer format( 84 double number, 85 StringBuffer result, 86 FieldPosition fieldPosition) { 87 pos[0] = fieldPosition; 88 return result; 89 } 90 }.format(0.0); 91 return pos[0]; 92 } 93 94 99 private static Map<String , Format> cache = 100 new LinkedHashMap<String , Format>() { 101 public boolean removeEldestEntry(Map.Entry<String , Format> entry) { 102 return size() > CacheLimit; 103 } 104 }; 105 106 static final char[] digits = { 107 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 108 }; 109 110 static final char thousandSeparator_en = ','; 111 static final char decimalPlaceholder_en = '.'; 112 static final String dateSeparator_en = "/"; 113 static final String timeSeparator_en = ":"; 114 static final String currencySymbol_en = "$"; 115 static final String currencyFormat_en = "$#,##0.00"; 116 static final String [] daysOfWeekShort_en = { 117 "", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 118 }; 119 static final String [] daysOfWeekLong_en = { 120 "", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 121 "Saturday" 122 }; 123 static final String [] monthsShort_en = { 124 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 125 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "", 126 }; 127 static final String [] monthsLong_en = { 128 "January", "February", "March", "April", "May", "June", 129 "July", "August", "September", "October", "November", "December", "", 130 }; 131 static final char intlCurrencySymbol = '\u08a4'; 132 133 137 private static final Map<String , FormatLocale> mapLocaleToFormatLocale = 138 new HashMap<String , FormatLocale>(); 139 140 144 static final FormatLocale locale_US = createLocale( 145 '\0', '\0', null, null, null, null, null, null, null, null, 146 Locale.US); 147 148 155 static String format(Object o, String formatString, Locale locale) 156 { 157 Format format = new Format(formatString, locale); 158 return format.format(o); 159 } 160 161 static class Token { 162 int code; 163 int flags; 164 String token; 165 166 Token(int code, int flags, String token) 167 { 168 this.code = code; 169 this.flags = flags; 170 this.token = token; 171 } 172 173 boolean isSpecial() 174 { 175 return (flags & SPECIAL) == SPECIAL; 176 } 177 178 boolean isNumeric() 179 { 180 return (flags & NUMERIC) == NUMERIC; 181 } 182 183 boolean isDate() 184 { 185 return (flags & DATE) == DATE; 186 } 187 188 boolean isString() 189 { 190 return (flags & STRING) == STRING; 191 } 192 193 BasicFormat makeFormat(FormatLocale locale) 194 { 195 if (isDate()) { 196 return new DateFormat(code, token, locale, false); 197 } else if (isNumeric()) { 198 return new LiteralFormat(code, token); 199 } else if (isString()) { 200 throw new Error (); 201 } else { 202 return new LiteralFormat(token); 203 } 204 } 205 } 206 207 220 static class BasicFormat { 221 int code; 222 223 BasicFormat() { 224 this(0); 225 } 226 227 BasicFormat(int code) { 228 this.code = code; 229 } 230 231 boolean isNumeric() { 232 return false; 233 } 234 235 boolean isDate() { 236 return false; 237 } 238 239 boolean isString() { 240 return false; 241 } 242 243 void formatNull(StringBuilder buf) { 244 } 245 246 void format(double d, StringBuilder buf) { 247 throw new Error (); 248 } 249 250 void format(long n, StringBuilder buf) { 251 throw new Error (); 252 } 253 254 void format(String s, StringBuilder buf) { 255 throw new Error (); 256 } 257 258 void format(Date date, StringBuilder buf) { 259 Calendar calendar = Calendar.getInstance(); calendar.setTime(date); 261 format(calendar, buf); 262 } 263 264 void format(Calendar calendar, StringBuilder buf) { 265 throw new Error (); 266 } 267 268 279 boolean isApplicableTo(double n) { 280 return true; 281 } 282 283 294 boolean isApplicableTo(long n) { 295 return true; 296 } 297 } 298 299 313 static class AlternateFormat extends BasicFormat { 314 final BasicFormat[] formats; 315 316 AlternateFormat(BasicFormat[] formats) 317 { 318 this.formats = formats; 319 assert formats.length >= 2; 320 } 321 322 void formatNull(StringBuilder buf) { 323 if (formats.length >= 4) { 324 formats[3].format(0, buf); 325 } else { 326 super.formatNull(buf); 327 } 328 } 329 330 void format(double n, StringBuilder buf) { 331 if (formats.length == 0) { 332 buf.append(n); 333 } else { 334 int i; 335 if (n == 0 && 336 formats.length >= 3 && 337 formats[2] != null) { 338 i = 2; 339 } else if (n < 0 && 340 formats.length >= 2 && 341 formats[1] != null) { 342 if (formats[1].isApplicableTo(n)) { 343 n = -n; 344 i = 1; 345 } else { 346 i = 2; 350 } 351 } else { 352 i = 0; 353 } 354 formats[i].format(n, buf); 355 } 356 } 357 358 void format(long n, StringBuilder buf) { 359 if (formats.length == 0) { 360 buf.append(n); 361 } else { 362 int i; 363 if (n == 0 && 364 formats.length >= 3 && 365 formats[2] != null) { 366 i = 2; 367 } else if (n < 0 && 368 formats.length >= 2 && 369 formats[1] != null && 370 formats[1].isApplicableTo(n)) { 371 n = -n; 372 i = 1; 373 } else { 374 i = 0; 375 } 376 formats[i].format(n, buf); 377 } 378 } 379 380 void format(String s, StringBuilder buf) { 381 formats[0].format(s, buf); 382 } 383 384 void format(Date date, StringBuilder buf) { 385 formats[0].format(date, buf); 386 } 387 388 void format(Calendar calendar, StringBuilder buf) { 389 formats[0].format(calendar, buf); 390 } 391 } 392 393 399 static class LiteralFormat extends BasicFormat 400 { 401 String s; 402 403 LiteralFormat(String s) 404 { 405 this(FORMAT_LITERAL, s); 406 } 407 408 LiteralFormat(int code, String s) 409 { 410 super(code); 411 this.s = s; 412 } 413 414 void format(double d, StringBuilder buf) { 415 buf.append(s); 416 } 417 418 void format(long n, StringBuilder buf) { 419 buf.append(s); 420 } 421 422 void format(String s, StringBuilder buf) { 423 buf.append(s); 424 } 425 426 void format(Date date, StringBuilder buf) { 427 buf.append(s); 428 } 429 430 void format(Calendar calendar, StringBuilder buf) { 431 buf.append(s); 432 } 433 } 434 435 442 static class CompoundFormat extends BasicFormat 443 { 444 final BasicFormat[] formats; 445 CompoundFormat(BasicFormat[] formats) 446 { 447 this.formats = formats; 448 assert formats.length >= 2; 449 } 450 451 void formatNull(StringBuilder buf) { 452 for (int i = 0; i < formats.length; i++) { 453 formats[i].formatNull(buf); 454 } 455 } 456 457 void format(double v, StringBuilder buf) { 458 for (int i = 0; i < formats.length; i++) { 459 formats[i].format(v, buf); 460 } 461 } 462 463 void format(long v, StringBuilder buf) { 464 for (int i = 0; i < formats.length; i++) { 465 formats[i].format(v, buf); 466 } 467 } 468 469 void format(String v, StringBuilder buf) { 470 for (int i = 0; i < formats.length; i++) { 471 formats[i].format(v, buf); 472 } 473 } 474 475 void format(Date v, StringBuilder buf) { 476 for (int i = 0; i < formats.length; i++) { 477 formats[i].format(v, buf); 478 } 479 } 480 481 void format(Calendar v, StringBuilder buf) { 482 for (int i = 0; i < formats.length; i++) { 483 formats[i].format(v, buf); 484 } 485 } 486 487 boolean isApplicableTo(double n) { 488 for (int i = 0; i < formats.length; i++) { 489 if (!formats[i].isApplicableTo(n)) { 490 return false; 491 } 492 } 493 return true; 494 } 495 496 } 497 498 503 static class JavaFormat extends BasicFormat 504 { 505 private final NumberFormat numberFormat; 506 private final java.text.DateFormat dateFormat; 507 508 JavaFormat(Locale locale) 509 { 510 this.numberFormat = NumberFormat.getNumberInstance(locale); 511 this.dateFormat = java.text.DateFormat.getDateInstance( 512 java.text.DateFormat.SHORT, locale); 513 } 514 515 518 void format(double d, StringBuilder buf) { 519 buf.append(numberFormat.format(d)); 522 } 523 524 void format(long n, StringBuilder buf) { 525 buf.append(numberFormat.format(n)); 528 } 529 530 void format(String s, StringBuilder buf) { 531 buf.append(s); 532 } 533 534 void format(Calendar calendar, StringBuilder buf) { 535 buf.append(dateFormat.format(calendar.getTime())); 538 } 539 } 540 541 546 static abstract class FallbackFormat extends BasicFormat 547 { 548 String token; 549 550 FallbackFormat(int code, String token) 551 { 552 super(code); 553 this.token = token; 554 } 555 556 void format(double d, StringBuilder buf) { 557 buf.append(token); 558 } 559 560 void format(long n, StringBuilder buf) { 561 buf.append(token); 562 } 563 564 void format(String s, StringBuilder buf) { 565 buf.append(token); 566 } 567 568 void format(Calendar calendar, StringBuilder buf) { 569 buf.append(token); 570 } 571 } 572 573 581 static class NumericFormat extends FallbackFormat 582 { 583 FormatLocale locale; 584 int digitsLeftOfPoint; 585 int zeroesLeftOfPoint; 586 int digitsRightOfPoint; 587 int zeroesRightOfPoint; 588 int digitsRightOfExp; 589 int zeroesRightOfExp; 590 591 596 int decimalShift; 597 char expChar; 598 boolean expSign; 599 boolean useDecimal; boolean useThouSep; 601 602 NumericFormat( 603 String token, FormatLocale locale, 604 int expFormat, 605 int digitsLeftOfPoint, int zeroesLeftOfPoint, 606 int digitsRightOfPoint, int zeroesRightOfPoint, 607 int digitsRightOfExp, int zeroesRightOfExp, 608 boolean useDecimal, boolean useThouSep) 609 { 610 super(FORMAT_NULL, token); 611 this.locale = locale; 612 switch (expFormat) { 613 case FORMAT_E_MINUS_UPPER: 614 this.expChar = 'E'; 615 this.expSign = false; 616 break; 617 case FORMAT_E_PLUS_UPPER: 618 this.expChar = 'E'; 619 this.expSign = true; 620 break; 621 case FORMAT_E_MINUS_LOWER: 622 this.expChar = 'e'; 623 this.expSign = false; 624 break; 625 case FORMAT_E_PLUS_LOWER: 626 this.expChar = 'e'; 627 this.expSign = true; 628 break; 629 default: 630 this.expChar = 0; 631 this.expSign = false; 632 } 633 this.digitsLeftOfPoint = digitsLeftOfPoint; 634 this.zeroesLeftOfPoint = zeroesLeftOfPoint; 635 this.digitsRightOfPoint = digitsRightOfPoint; 636 this.zeroesRightOfPoint = zeroesRightOfPoint; 637 this.digitsRightOfExp = digitsRightOfExp; 638 this.zeroesRightOfExp = zeroesRightOfExp; 639 this.useDecimal = useDecimal; 640 this.useThouSep = useThouSep; 641 this.decimalShift = 0; } 643 644 void format(double n, StringBuilder buf) 645 { 646 FloatingDecimal fd = new FloatingDecimal(n); 647 fd.shift(decimalShift); 648 final int formatDigitsRightOfPoint = 649 zeroesRightOfPoint + digitsRightOfPoint; 650 if (n < 0 && !shows(fd, formatDigitsRightOfPoint)) { 651 n = 0; 654 fd = new FloatingDecimal(0); 655 } 656 String s = fd.toJavaFormatString( 657 zeroesLeftOfPoint, 658 locale.decimalPlaceholder, 659 zeroesRightOfPoint, 660 formatDigitsRightOfPoint, 661 expChar, 662 expSign, 663 zeroesRightOfExp, 664 useThouSep ? locale.thousandSeparator : '\0'); 665 buf.append(s); 666 } 667 668 boolean isApplicableTo(double n) { 669 if (n >= 0) { 670 return true; 671 } 672 FloatingDecimal fd = new FloatingDecimal(n); 673 fd.shift(decimalShift); 674 final int formatDigitsRightOfPoint = 675 zeroesRightOfPoint + digitsRightOfPoint; 676 return shows(fd, formatDigitsRightOfPoint); 677 } 678 679 private static boolean shows( 680 FloatingDecimal fd, int formatDigitsRightOfPoint) { 681 final int i0 = - fd.decExponent - formatDigitsRightOfPoint; 682 if (i0 < 0) { 683 return true; 684 } 685 if (i0 > 0) { 686 return false; 687 } 688 for (int i = i0; i < fd.nDigits; ++i) { 689 final char digit = fd.digits[i]; 690 if (i == i0) { 691 if (digit > '5') { 692 return true; 693 } 694 if (digit < '5') { 695 return false; 696 } 697 } else { 698 if (digit > '0') { 699 return true; 700 } 701 } 702 } 703 return false; 704 } 705 706 void format(long n, StringBuilder buf) 707 { 708 mondrian.util.Format.FloatingDecimal fd 709 = new mondrian.util.Format.FloatingDecimal(n); 710 fd.shift(decimalShift); 711 String s = fd.toJavaFormatString( 712 zeroesLeftOfPoint, 713 locale.decimalPlaceholder, 714 zeroesRightOfPoint, 715 zeroesRightOfPoint + digitsRightOfPoint, 716 expChar, 717 expSign, 718 zeroesRightOfExp, 719 useThouSep ? locale.thousandSeparator : '\0'); 720 buf.append(s); 721 } 722 } 723 724 736 static class DateFormat extends FallbackFormat 737 { 738 FormatLocale locale; 739 boolean twelveHourClock; 740 741 DateFormat(int code, String s, FormatLocale locale, boolean twelveHourClock) 742 { 743 super(code, s); 744 this.locale = locale; 745 this.twelveHourClock = twelveHourClock; 746 } 747 748 void setTwelveHourClock(boolean twelveHourClock) 749 { 750 this.twelveHourClock = twelveHourClock; 751 } 752 753 void format(Calendar calendar, StringBuilder buf) 754 { 755 format(code, calendar, buf); 756 } 757 758 private void format(int code, Calendar calendar, StringBuilder buf) 759 { 760 switch (code) { 761 case FORMAT_C: 762 { 763 boolean dateSet = !( 764 calendar.get(Calendar.DAY_OF_YEAR) == 0 && 765 calendar.get(Calendar.YEAR) == 0); 766 boolean timeSet = !( 767 calendar.get(Calendar.SECOND) == 0 && 768 calendar.get(Calendar.MINUTE) == 0 && 769 calendar.get(Calendar.HOUR) == 0); 770 if (dateSet) { 771 format(FORMAT_DDDDD, calendar, buf); 772 } 773 if (dateSet && timeSet) { 774 buf.append(' '); 775 } 776 if (timeSet) { 777 format(FORMAT_TTTTT, calendar, buf); 778 } 779 break; 780 } 781 case FORMAT_D: 782 { 783 int d = calendar.get(Calendar.DAY_OF_MONTH); 784 buf.append(d); 785 break; 786 } 787 case FORMAT_DD: 788 { 789 int d = calendar.get(Calendar.DAY_OF_MONTH); 790 if (d < 10) { 791 buf.append('0'); 792 } 793 buf.append(d); 794 break; 795 } 796 case FORMAT_DDD: 797 { 798 int dow = calendar.get(Calendar.DAY_OF_WEEK); 799 buf.append(locale.daysOfWeekShort[dow]); break; 801 } 802 case FORMAT_DDDD: 803 { 804 int dow = calendar.get(Calendar.DAY_OF_WEEK); 805 buf.append(locale.daysOfWeekLong[dow]); break; 807 } 808 case FORMAT_DDDDD: 809 { 810 format(FORMAT_M, calendar,buf); 814 buf.append(locale.dateSeparator); 815 format(FORMAT_D, calendar,buf); 816 buf.append(locale.dateSeparator); 817 format(FORMAT_YY, calendar,buf); 818 break; 819 } 820 case FORMAT_DDDDDD: 821 { 822 format(FORMAT_MMMM_UPPER, calendar, buf); 823 buf.append(" "); 824 format(FORMAT_DD, calendar, buf); 825 buf.append(", "); 826 format(FORMAT_YYYY, calendar, buf); 827 break; 828 } 829 case FORMAT_W: 830 { 831 int dow = calendar.get(Calendar.DAY_OF_WEEK); 832 buf.append(dow); 833 break; 834 } 835 case FORMAT_WW: 836 { 837 int woy = calendar.get(Calendar.WEEK_OF_YEAR); 838 buf.append(woy); 839 break; 840 } 841 case FORMAT_M: 842 { 843 int m = calendar.get(Calendar.MONTH) + 1; buf.append(m); 845 break; 846 } 847 case FORMAT_MM: 848 { 849 int mm = calendar.get(Calendar.MONTH) + 1; if (mm < 10) { 851 buf.append('0'); 852 } 853 buf.append(mm); 854 break; 855 } 856 case FORMAT_MMM_LOWER: 857 case FORMAT_MMM_UPPER: 858 { 859 int m = calendar.get(Calendar.MONTH); buf.append(locale.monthsShort[m]); break; 862 } 863 case FORMAT_MMMM_LOWER: 864 case FORMAT_MMMM_UPPER: 865 { 866 int m = calendar.get(Calendar.MONTH); buf.append(locale.monthsLong[m]); break; 869 } 870 case FORMAT_Q: 871 { 872 int m = calendar.get(Calendar.MONTH); 873 int q = m / 3 + 1; 875 buf.append(q); 876 break; 877 } 878 case FORMAT_Y: 879 { 880 int doy = calendar.get(Calendar.DAY_OF_YEAR); 881 buf.append(doy); 882 break; 883 } 884 case FORMAT_YY: 885 { 886 int y = calendar.get(Calendar.YEAR) % 100; 887 if (y < 10) { 888 buf.append('0'); 889 } 890 buf.append(y); 891 break; 892 } 893 case FORMAT_YYYY: 894 { 895 int y = calendar.get(Calendar.YEAR); 896 buf.append(y); 897 break; 898 } 899 case FORMAT_H: 900 { 901 int h = calendar.get( 902 twelveHourClock ? Calendar.HOUR : Calendar.HOUR_OF_DAY); 903 buf.append(h); 904 break; 905 } 906 case FORMAT_HH: 907 { 908 int h = calendar.get( 909 twelveHourClock ? Calendar.HOUR : Calendar.HOUR_OF_DAY); 910 if (h < 10) { 911 buf.append('0'); 912 } 913 buf.append(h); 914 break; 915 } 916 case FORMAT_N: 917 { 918 int n = calendar.get(Calendar.MINUTE); 919 buf.append(n); 920 break; 921 } 922 case FORMAT_NN: 923 { 924 int n = calendar.get(Calendar.MINUTE); 925 if (n < 10) { 926 buf.append('0'); 927 } 928 buf.append(n); 929 break; 930 } 931 case FORMAT_S: 932 { 933 int s = calendar.get(Calendar.SECOND); 934 buf.append(s); 935 break; 936 } 937 case FORMAT_SS: 938 { 939 int s = calendar.get(Calendar.SECOND); 940 if (s < 10) { 941 buf.append('0'); 942 } 943 buf.append(s); 944 break; 945 } 946 case FORMAT_TTTTT: 947 { 948 format(FORMAT_H, calendar,buf); 951 buf.append(locale.timeSeparator); 952 format(FORMAT_NN, calendar,buf); 953 buf.append(locale.timeSeparator); 954 format(FORMAT_SS, calendar,buf); 955 break; 956 } 957 case FORMAT_AMPM: 958 case FORMAT_UPPER_AM_SOLIDUS_PM: 959 { 960 boolean isAm = calendar.get(Calendar.AM_PM) == Calendar.AM; 961 buf.append(isAm ? "AM" : "PM"); 962 break; 963 } 964 case FORMAT_LOWER_AM_SOLIDUS_PM: 965 { 966 boolean isAm = calendar.get(Calendar.AM_PM) == Calendar.AM; 967 buf.append(isAm ? "am" : "pm"); 968 break; 969 } 970 case FORMAT_UPPER_A_SOLIDUS_P: 971 { 972 boolean isAm = calendar.get(Calendar.AM_PM) == Calendar.AM; 973 buf.append(isAm ? "A" : "P"); 974 break; 975 } 976 case FORMAT_LOWER_A_SOLIDUS_P: 977 { 978 boolean isAm = calendar.get(Calendar.AM_PM) == Calendar.AM; 979 buf.append(isAm ? "a" : "p"); 980 break; 981 } 982 default: 983 throw new Error (); 984 } 985 } 986 } 987 988 993 public static class FormatLocale 994 { 995 char thousandSeparator; 996 char decimalPlaceholder; 997 String dateSeparator; 998 String timeSeparator; 999 String currencySymbol; 1000 String currencyFormat; 1001 String [] daysOfWeekShort; 1002 String [] daysOfWeekLong; 1003 String [] monthsShort; 1004 String [] monthsLong; 1005 private final Locale locale; 1006 1007 private FormatLocale( 1008 char thousandSeparator, 1009 char decimalPlaceholder, 1010 String dateSeparator, 1011 String timeSeparator, 1012 String currencySymbol, 1013 String currencyFormat, 1014 String [] daysOfWeekShort, 1015 String [] daysOfWeekLong, 1016 String [] monthsShort, 1017 String [] monthsLong, 1018 Locale locale) 1019 { 1020 this.locale = locale; 1021 if (thousandSeparator == '\0') { 1022 thousandSeparator = thousandSeparator_en; 1023 } 1024 this.thousandSeparator = thousandSeparator; 1025 if (decimalPlaceholder == '\0') { 1026 decimalPlaceholder = decimalPlaceholder_en; 1027 } 1028 this.decimalPlaceholder = decimalPlaceholder; 1029 if (dateSeparator == null) { 1030 dateSeparator = dateSeparator_en; 1031 } 1032 this.dateSeparator = dateSeparator; 1033 if (timeSeparator == null) { 1034 timeSeparator = timeSeparator_en; 1035 } 1036 this.timeSeparator = timeSeparator; 1037 if (currencySymbol == null) { 1038 currencySymbol = currencySymbol_en; 1039 } 1040 this.currencySymbol = currencySymbol; 1041 if (currencyFormat == null) { 1042 currencyFormat = currencyFormat_en; 1043 } 1044 this.currencyFormat = currencyFormat; 1045 if (daysOfWeekShort == null) { 1046 daysOfWeekShort = daysOfWeekShort_en; 1047 } 1048 this.daysOfWeekShort = daysOfWeekShort; 1049 if (daysOfWeekLong == null) { 1050 daysOfWeekLong = daysOfWeekLong_en; 1051 } 1052 this.daysOfWeekLong = daysOfWeekLong; 1053 if (monthsShort == null) { 1054 monthsShort = monthsShort_en; 1055 } 1056 this.monthsShort = monthsShort; 1057 if (monthsLong == null) { 1058 monthsLong = monthsLong_en; 1059 } 1060 this.monthsLong = monthsLong; 1061 if (daysOfWeekShort.length != 8 || 1062 daysOfWeekLong.length != 8 || 1063 monthsShort.length != 13 || 1064 monthsLong.length != 13) { 1065 throw new IllegalArgumentException ( 1066 "Format: day or month array has incorrect length"); 1067 } 1068 } 1069 1070 1090 1115 1125 1130 1133 1143 1146 1152 } 1153 1154 private static class StringFormat extends BasicFormat 1155 { 1156 int stringCase; 1157 1158 StringFormat(int stringCase) { 1159 this.stringCase = stringCase; 1160 } 1161 } 1162 1163 1164 private static final int CASE_ASIS = 0; 1165 private static final int CASE_UPPER = 1; 1166 private static final int CASE_LOWER = 2; 1167 1168 1169 private static final int GENERAL = 0; 1170 private static final int DATE = 3; 1171 private static final int NUMERIC = 4; 1172 private static final int STRING = 5; 1173 1175 private static final int SPECIAL = 8; 1176 1177 1178 private static final int FORMAT_NULL = 0; 1179 private static final int FORMAT_C = 3; 1180 private static final int FORMAT_D = 4; 1181 private static final int FORMAT_DD = 5; 1182 private static final int FORMAT_DDD = 6; 1183 private static final int FORMAT_DDDD = 7; 1184 private static final int FORMAT_DDDDD = 8; 1185 private static final int FORMAT_DDDDDD = 9; 1186 private static final int FORMAT_W = 10; 1187 private static final int FORMAT_WW = 11; 1188 private static final int FORMAT_M = 12; 1189 private static final int FORMAT_MM = 13; 1190 private static final int FORMAT_MMM_UPPER = 14; 1191 private static final int FORMAT_MMMM_UPPER = 15; 1192 private static final int FORMAT_Q = 16; 1193 private static final int FORMAT_Y = 17; 1194 private static final int FORMAT_YY = 18; 1195 private static final int FORMAT_YYYY = 19; 1196 private static final int FORMAT_H = 20; 1197 private static final int FORMAT_HH = 21; 1198 private static final int FORMAT_N = 22; 1199 private static final int FORMAT_NN = 23; 1200 private static final int FORMAT_S = 24; 1201 private static final int FORMAT_SS = 25; 1202 private static final int FORMAT_TTTTT = 26; 1203 private static final int FORMAT_UPPER_AM_SOLIDUS_PM = 27; 1204 private static final int FORMAT_LOWER_AM_SOLIDUS_PM = 28; 1205 private static final int FORMAT_UPPER_A_SOLIDUS_P = 29; 1206 private static final int FORMAT_LOWER_A_SOLIDUS_P = 30; 1207 private static final int FORMAT_AMPM = 31; 1208 private static final int FORMAT_0 = 32; 1209 private static final int FORMAT_POUND = 33; 1210 private static final int FORMAT_DECIMAL = 34; 1211 private static final int FORMAT_PERCENT = 35; 1212 private static final int FORMAT_THOUSEP = 36; 1213 private static final int FORMAT_TIMESEP = 37; 1214 private static final int FORMAT_DATESEP = 38; 1215 private static final int FORMAT_E_MINUS_UPPER = 39; 1216 private static final int FORMAT_E_PLUS_UPPER = 40; 1217 private static final int FORMAT_E_MINUS_LOWER = 41; 1218 private static final int FORMAT_E_PLUS_LOWER = 42; 1219 private static final int FORMAT_LITERAL = 43; 1220 private static final int FORMAT_BACKSLASH = 44; 1221 private static final int FORMAT_QUOTE = 45; 1222 private static final int FORMAT_CHARACTER_OR_SPACE = 46; 1223 private static final int FORMAT_CHARACTER_OR_NOTHING = 47; 1224 private static final int FORMAT_LOWER = 48; 1225 private static final int FORMAT_UPPER = 49; 1226 private static final int FORMAT_FILL_FROM_LEFT = 50; 1227 private static final int FORMAT_SEMI = 51; 1228 private static final int FORMAT_GENERAL_NUMBER = 52; 1229 private static final int FORMAT_GENERAL_DATE = 53; 1230 private static final int FORMAT_INTL_CURRENCY = 54; 1231 private static final int FORMAT_MMM_LOWER = 55; 1232 private static final int FORMAT_MMMM_LOWER = 56; 1233 private static final int FORMAT_USD = 57; 1234 1235 private static final Token nfe( 1236 int code, int flags, String token, String purpose, String description) 1237 { 1238 Util.discard(purpose); 1239 Util.discard(description); 1240 return new Token(code,flags,token); 1241 } 1242 1243 public static final List<Token> getTokenList() 1244 { 1245 return Collections.unmodifiableList(Arrays.asList(tokens)); 1246 } 1247 1248 static final Token[] tokens = { 1249 nfe(FORMAT_NULL , NUMERIC, null, "No formatting", "Display the number with no formatting."), 1250 nfe(FORMAT_C , DATE, "C", null, "Display the date as ddddd and display the time as t t t t t, in that order. Display only date information if there is no fractional part to the date serial number; display only time information if there is no integer portion."), 1251 nfe(FORMAT_D , DATE, "d", null, "Display the day as a number without a leading zero (1 - 31)."), 1252 nfe(FORMAT_DD , DATE, "dd", null, "Display the day as a number with a leading zero (01 - 31)."), 1253 nfe(FORMAT_DDD , DATE, "Ddd", null, "Display the day as an abbreviation (Sun - Sat)."), 1254 nfe(FORMAT_DDDD , DATE, "dddd", null, "Display the day as a full name (Sunday - Saturday)."), 1255 nfe(FORMAT_DDDDD , DATE, "ddddd", null, "Display the date as a complete date (including day, month, and year), formatted according to your system's short date format setting. The default short date format is m/d/yy."), 1256 nfe(FORMAT_DDDDDD , DATE, "dddddd", null, "Display a date serial number as a complete date (including day, month, and year) formatted according to the long date setting recognized by your system. The default long date format is mmmm dd, yyyy."), 1257 nfe(FORMAT_W , DATE, "w", null, "Display the day of the week as a number (1 for Sunday through 7 for Saturday)."), 1258 nfe(FORMAT_WW , DATE, "ww", null, "Display the week of the year as a number (1 - 53)."), 1259 nfe(FORMAT_M , DATE | SPECIAL, "m", null, "Display the month as a number without a leading zero (1 - 12). If m immediately follows h or hh, the minute rather than the month is displayed."), 1260 nfe(FORMAT_MM , DATE | SPECIAL, "mm", null, "Display the month as a number with a leading zero (01 - 12). If m immediately follows h or hh, the minute rather than the month is displayed."), 1261 nfe(FORMAT_MMM_LOWER , DATE, "mmm", null, "Display the month as an abbreviation (Jan - Dec)."), 1262 nfe(FORMAT_MMMM_LOWER , DATE, "mmmm", null, "Display the month as a full month name (January - December)."), 1263 nfe(FORMAT_MMM_UPPER , DATE, "mmm", null, "Display the month as an abbreviation (Jan - Dec)."), 1264 nfe(FORMAT_MMMM_UPPER , DATE, "mmmm", null, "Display the month as a full month name (January - December)."), 1265 nfe(FORMAT_Q , DATE, "q", null, "Display the quarter of the year as a number (1 - 4)."), 1266 nfe(FORMAT_Y , DATE, "y", null, "Display the day of the year as a number (1 - 366)."), 1267 nfe(FORMAT_YY , DATE, "yy", null, "Display the year as a 2-digit number (00 - 99)."), 1268 nfe(FORMAT_YYYY , DATE, "yyyy", null, "Display the year as a 4-digit number (100 - 9999)."), 1269 nfe(FORMAT_H , DATE, "h", null, "Display the hour as a number without leading zeros (0 - 23)."), 1270 nfe(FORMAT_HH , DATE, "hh", null, "Display the hour as a number with leading zeros (00 - 23)."), 1271 nfe(FORMAT_N , DATE, "n", null, "Display the minute as a number without leading zeros (0 - 59)."), 1272 nfe(FORMAT_NN , DATE, "nn", null, "Display the minute as a number with leading zeros (00 - 59)."), 1273 nfe(FORMAT_S , DATE, "s", null, "Display the second as a number without leading zeros (0 - 59)."), 1274 nfe(FORMAT_SS , DATE, "ss", null, "Display the second as a number with leading zeros (00 - 59)."), 1275 nfe(FORMAT_TTTTT , DATE, "ttttt", null, "Display a time as a complete time (including hour, minute, and second), formatted using the time separator defined by the time format recognized by your system. A leading zero is displayed if the leading zero option is selected and the time is before 10:00 A.M. or P.M. The default time format is h:mm:ss."), 1276 nfe(FORMAT_UPPER_AM_SOLIDUS_PM , DATE, "AM/PM", null, "Use the 12-hour clock and display an uppercase AM with any hour before noon; display an uppercase PM with any hour between noon and 11:59 P.M."), 1277 nfe(FORMAT_LOWER_AM_SOLIDUS_PM , DATE, "am/pm", null, "Use the 12-hour clock and display a lowercase AM with any hour before noon; display a lowercase PM with any hour between noon and 11:59 P.M."), 1278 nfe(FORMAT_UPPER_A_SOLIDUS_P , DATE, "A/P", null, "Use the 12-hour clock and display an uppercase A with any hour before noon; display an uppercase P with any hour between noon and 11:59 P.M."), 1279 nfe(FORMAT_LOWER_A_SOLIDUS_P , DATE, "a/p", null, "Use the 12-hour clock and display a lowercase A with any hour before noon; display a lowercase P with any hour between noon and 11:59 P.M."), 1280 nfe(FORMAT_AMPM , DATE, "AMPM", null, "Use the 12-hour clock and display the AM string literal as defined by your system with any hour before noon; display the PM string literal as defined by your system with any hour between noon and 11:59 P.M. AMPM can be either uppercase or lowercase, but the case of the string displayed matches the string as defined by your system settings. The default format is AM/PM."), 1281 nfe(FORMAT_0 , NUMERIC | SPECIAL, "0", "Digit placeholder", "Display a digit or a zero. If the expression has a digit in the position where the 0 appears in the format string, display it; otherwise, display a zero in that position. If the number has fewer digits than there are zeros (on either side of the decimal) in the format expression, display leading or trailing zeros. If the number has more digits to the right of the decimal separator than there are zeros to the right of the decimal separator in the format expression, round the number to as many decimal places as there are zeros. If the number has more digits to the left of the decimal separator than there are zeros to the left of the decimal separator in the format expression, display the extra digits without modification."), 1282 nfe(FORMAT_POUND , NUMERIC | SPECIAL, "#", "Digit placeholder", "Display a digit or nothing. If the expression has a digit in the position where the # appears in the format string, display it; otherwise, display nothing in that position. This symbol works like the 0 digit placeholder, except that leading and trailing zeros aren't displayed if the number has the same or fewer digits than there are # characters on either side of the decimal separator in the format expression."), 1283 nfe(FORMAT_DECIMAL , NUMERIC | SPECIAL, ".", "Decimal placeholder", "In some locales, a comma is used as the decimal separator. The decimal placeholder determines how many digits are displayed to the left and right of the decimal separator. If the format expression contains only number signs to the left of this symbol, numbers smaller than 1 begin with a decimal separator. If you always want a leading zero displayed with fractional numbers, use 0 as the first digit placeholder to the left of the decimal separator instead. The actual character used as a decimal placeholder in the formatted output depends on the Number Format recognized by your system."), 1284 nfe(FORMAT_PERCENT , NUMERIC, "%", "Percent placeholder", "The expression is multiplied by 100. The percent character (%) is inserted in the position where it appears in the format string."), 1285 nfe(FORMAT_THOUSEP , NUMERIC | SPECIAL, ",", "Thousand separator", "In some locales, a period is used as a thousand separator. The thousand separator separates thousands from hundreds within a number that has four or more places to the left of the decimal separator. Standard use of the thousand separator is specified if the format contains a thousand separator surrounded by digit placeholders (0 or #). Two adjacent thousand separators or a thousand separator immediately to the left of the decimal separator (whether or not a decimal is specified) means \"scale the number by dividing it by 1000, rounding as needed.\" You can scale large numbers using this technique. For example, you can use the format string \"##0,,\" to represent 100 million as 100. Numbers smaller than 1 million are displayed as 0. Two adjacent thousand separators in any position other than immediately to the left of the decimal separator are treated simply as specifying the use of a thousand separator. The actual character used as the thousand separator in the formatted output depends on the Number Format recognized by your system."), 1286 nfe(FORMAT_TIMESEP , DATE | SPECIAL, ":", "Time separator", "In some locales, other characters may be used to represent the time separator. The time separator separates hours, minutes, and seconds when time values are formatted. The actual character used as the time separator in formatted output is determined by your system settings."), 1287 nfe(FORMAT_DATESEP , DATE | SPECIAL, "/", "Date separator", "In some locales, other characters may be used to represent the date separator. The date separator separates the day, month, and year when date values are formatted. The actual character used as the date separator in formatted output is determined by your system settings."), 1288 nfe(FORMAT_E_MINUS_UPPER , NUMERIC | SPECIAL, "E-", "Scientific format", "If the format expression contains at least one digit placeholder (0 or #) to the right of E-, E+, e-, or e+, the number is displayed in scientific format and E or e is inserted between the number and its exponent. The number of digit placeholders to the right determines the number of digits in the exponent. Use E- or e- to place a minus sign next to negative exponents. Use E+ or e+ to place a minus sign next to negative exponents and a plus sign next to positive exponents."), 1289 nfe(FORMAT_E_PLUS_UPPER , NUMERIC | SPECIAL, "E+", "Scientific format", "See E-."), 1290 nfe(FORMAT_E_MINUS_LOWER , NUMERIC | SPECIAL, "e-", "Scientific format", "See E-."), 1291 nfe(FORMAT_E_PLUS_LOWER , NUMERIC | SPECIAL, "e+", "Scientific format", "See E-."), 1292 nfe(FORMAT_LITERAL , GENERAL, "-", "Display a literal character", "To display a character other than one of those listed, precede it with a backslash (\\) or enclose it in double quotation marks (\" \")."), 1293 nfe(FORMAT_LITERAL , GENERAL, "+", "Display a literal character", "See -."), 1294 nfe(FORMAT_LITERAL , GENERAL, "$", "Display a literal character", "See -."), 1295 nfe(FORMAT_LITERAL , GENERAL, "(", "Display a literal character", "See -."), 1296 nfe(FORMAT_LITERAL , GENERAL, ")", "Display a literal character", "See -."), 1297 nfe(FORMAT_LITERAL , GENERAL, " ", "Display a literal character", "See -."), 1298 nfe(FORMAT_BACKSLASH , GENERAL | SPECIAL, "\\", "Display the next character in the format string", "Many characters in the format expression have a special meaning and can't be displayed as literal characters unless they are preceded by a backslash. The backslash itself isn't displayed. Using a backslash is the same as enclosing the next character in double quotation marks. To display a backslash, use two backslashes (\\). Examples of characters that can't be displayed as literal characters are the date- and time-formatting characters (a, c, d, h, m, n, p, q, s, t, w, y, and /:), the numeric-formatting characters (#, 0, %, E, e, comma, and period), and the string-formatting characters (@, &, <, >, and !)."), 1299 nfe(FORMAT_QUOTE , GENERAL | SPECIAL, "\"", "Display the string inside the double quotation marks", "To include a string in format from within code, you must use Chr(34) to enclose the text (34 is the character code for a double quotation mark)."), 1300 nfe(FORMAT_CHARACTER_OR_SPACE , STRING, "@", "Character placeholder", "Display a character or a space. If the string has a character in the position where the @ appears in the format string, display it; otherwise, display a space in that position. Placeholders are filled from right to left unless there is an ! character in the format string. See below."), 1301 nfe(FORMAT_CHARACTER_OR_NOTHING, STRING, "&", "Character placeholder", "Display a character or nothing. If the string has a character in the position where the & appears, display it; otherwise, display nothing. Placeholders are filled from right to left unless there is an ! character in the format string. See below."), 1302 nfe(FORMAT_LOWER , STRING | SPECIAL, "<", "Force lowercase", "Display all characters in lowercase format."), 1303 nfe(FORMAT_UPPER , STRING | SPECIAL, ">", "Force uppercase", "Display all characters in uppercase format."), 1304 nfe(FORMAT_FILL_FROM_LEFT , STRING | SPECIAL, "!", "Force left to right fill of placeholders", "The default is to fill from right to left."), 1305 nfe(FORMAT_SEMI , GENERAL | SPECIAL, ";", "Separates format strings for different kinds of values", "If there is one section, the format expression applies to all values. If there are two sections, the first section applies to positive values and zeros, the second to negative values. If there are three sections, the first section applies to positive values, the second to negative values, and the third to zeros. If there are four sections, the first section applies to positive values, the second to negative values, the third to zeros, and the fourth to Null values."), 1306 nfe(FORMAT_INTL_CURRENCY , NUMERIC | SPECIAL, intlCurrencySymbol + "", null, "Display the locale's currency symbol."), 1307 nfe(FORMAT_USD , GENERAL, "USD", null, "Display USD (U.S. Dollars)."), 1308 nfe(FORMAT_GENERAL_NUMBER , NUMERIC | SPECIAL, "General Number", null, "Shows numbers as entered."), 1309 nfe(FORMAT_GENERAL_DATE , DATE | SPECIAL, "General Date", null, "Shows date and time if expression contains both. If expression is only a date or a time, the missing information is not displayed."), 1310 }; 1311 1312 static class MacroToken { 1313 String name; 1314 String translation; 1315 String description; 1316 1317 MacroToken(String name, String translation, String description) 1318 { 1319 this.name = name; 1320 this.translation = translation; 1321 this.description = description; 1322 } 1323 } 1324 1325 private static final MacroToken[] macroTokens = { 1327 new MacroToken( 1328 "Currency", null, "Shows currency values according to the locale's CurrencyFormat. Negative numbers are inside parentheses."), 1329 new MacroToken( 1330 "Fixed", "0", "Shows at least one digit."), 1331 new MacroToken( 1332 "Standard", "#,##0", "Uses a thousands separator."), 1333 new MacroToken( 1334 "Percent", "0.00%", "Multiplies the value by 100 with a percent sign at the end."), 1335 new MacroToken( 1336 "Scientific", "0.00e+00", "Uses standard scientific notation."), 1337 new MacroToken( 1338 "Long Date", "dddd, mmmm dd, yyyy", "Uses the Long Date format specified in the Regional Settings dialog box of the Microsoft Windows Control Panel."), 1339 new MacroToken( 1340 "Medium Date", "dd-mmm-yy", "Uses the dd-mmm-yy format (for example, 03-Apr-93)"), 1341 new MacroToken( 1342 "Short Date", "m/d/yy", "Uses the Short Date format specified in the Regional Settings dialog box of the Windows Control Panel."), 1343 new MacroToken( 1344 "Long Time", "h:mm:ss AM/PM", "Shows the hour, minute, second, and \"AM\" or \"PM\" using the h:mm:ss format."), 1345 new MacroToken( 1346 "Medium Time", "h:mm AM/PM", "Shows the hour, minute, and \"AM\" or \"PM\" using the \"hh:mm AM/PM\" format."), 1347 new MacroToken( 1348 "Short Time", "hh:mm", "Shows the hour and minute using the hh:mm format."), 1349 new MacroToken( 1350 "Yes/No", "\\Y\\e\\s;\\Y\\e\\s;\\N\\o;\\N\\o", "Any nonzero numeric value (usually - 1) is Yes. Zero is No."), 1351 new MacroToken( 1352 "True/False", "\\T\\r\\u\\e;\\T\\r\\u\\e;\\F\\a\\l\\s\\e;\\F\\a\\l\\s\\e", "Any nonzero numeric value (usually - 1) is True. Zero is False."), 1353 new MacroToken( 1354 "On/Off", "\\O\\n;\\O\\n;\\O\\f\\f;\\O\\f\\f", "Any nonzero numeric value (usually - 1) is On. Zero is Off."), 1355 1356 }; 1357 1358 1366 public Format(String formatString, Locale locale) 1367 { 1368 this(formatString, getBestFormatLocale(locale)); 1369 } 1370 1371 1377 public Format(String formatString, FormatLocale locale) 1378 { 1379 if (formatString == null) { 1380 formatString = ""; 1381 } 1382 this.formatString = formatString; 1383 if (locale == null) { 1384 locale = locale_US; 1385 } 1386 this.locale = locale; 1387 1388 List<BasicFormat> alternateFormatList = new ArrayList<BasicFormat>(); 1389 while (formatString.length() > 0) { 1390 formatString = parseFormatString( 1391 formatString, alternateFormatList); 1392 } 1393 1394 if (alternateFormatList.size() == 0 || alternateFormatList.get(0) == null) { 1398 format = new JavaFormat(locale.locale); 1399 } else if (alternateFormatList.size() == 1) { 1400 format = (BasicFormat) alternateFormatList.get(0); 1401 } else { 1402 BasicFormat[] alternateFormats = 1403 (BasicFormat[]) alternateFormatList.toArray( 1404 new BasicFormat[alternateFormatList.size()]); 1405 format = new AlternateFormat(alternateFormats); 1406 } 1407 } 1408 1409 1420 public static Format get(String formatString, Locale locale) { 1421 String key = formatString + "@@@" + locale; 1422 Format format = (Format) cache.get(key); 1423 if (format == null) { 1424 synchronized (cache) { 1425 format = (Format) cache.get(key); 1426 if (format == null) { 1427 format = new Format(formatString, locale); 1428 cache.put(key, format); 1429 } 1430 } 1431 } 1432 return format; 1433 } 1434 1435 1470 public static FormatLocale createLocale( 1471 char thousandSeparator, 1472 char decimalPlaceholder, 1473 String dateSeparator, 1474 String timeSeparator, 1475 String currencySymbol, 1476 String currencyFormat, 1477 String [] daysOfWeekShort, 1478 String [] daysOfWeekLong, 1479 String [] monthsShort, 1480 String [] monthsLong, 1481 Locale locale) 1482 { 1483 FormatLocale formatLocale = new FormatLocale( 1484 thousandSeparator, decimalPlaceholder, dateSeparator, 1485 timeSeparator, currencySymbol, currencyFormat, daysOfWeekShort, 1486 daysOfWeekLong, monthsShort, monthsLong, locale); 1487 if (locale != null) { 1488 registerFormatLocale(formatLocale, locale); 1489 } 1490 return formatLocale; 1491 } 1492 1493 public static FormatLocale createLocale(Locale locale) 1494 { 1495 final DecimalFormatSymbols decimalSymbols = 1496 new DecimalFormatSymbols(locale); 1497 final DateFormatSymbols dateSymbols = new DateFormatSymbols(locale); 1498 1499 Calendar calendar = Calendar.getInstance(locale); 1500 calendar.set(1969, 11, 31, 0, 0, 0); 1501 final Date date = calendar.getTime(); 1502 1503 final java.text.DateFormat dateFormat = 1504 java.text.DateFormat.getDateInstance( 1505 java.text.DateFormat.SHORT, locale); 1506 final String dateValue = dateFormat.format(date); String dateSeparator = dateValue.substring(2, 3); 1509 final java.text.DateFormat timeFormat = 1510 java.text.DateFormat.getTimeInstance( 1511 java.text.DateFormat.SHORT, locale); 1512 final String timeValue = timeFormat.format(date); String timeSeparator = timeValue.substring(2, 3); 1515 final NumberFormat currencyFormat = 1518 NumberFormat.getCurrencyInstance(locale); 1519 final String currencyValue = currencyFormat.format(123456.78); 1520 String currencyLeft = 1521 currencyValue.substring(0, currencyValue.indexOf("1")); 1522 String currencyRight = 1523 currencyValue.substring(currencyValue.indexOf("8") + 1); 1524 StringBuilder buf = new StringBuilder (); 1525 buf.append(currencyLeft); 1526 int minimumIntegerDigits = currencyFormat.getMinimumIntegerDigits(); 1527 for (int i = Math.max(minimumIntegerDigits, 4) - 1; i >= 0; --i) { 1528 buf.append(i < minimumIntegerDigits ? '0' : '#'); 1529 if (i % 3 == 0 && i > 0) { 1530 buf.append(','); 1531 } 1532 } 1533 if (currencyFormat.getMaximumFractionDigits() > 0) { 1534 buf.append('.'); 1535 appendTimes(buf, '0', currencyFormat.getMinimumFractionDigits()); 1536 appendTimes(buf, '#', 1537 currencyFormat.getMaximumFractionDigits() - 1538 currencyFormat.getMinimumFractionDigits()); 1539 } 1540 buf.append(currencyRight); 1541 String currencyFormatString = buf.toString(); 1542 1543 return createLocale( 1544 decimalSymbols.getGroupingSeparator(), 1545 decimalSymbols.getDecimalSeparator(), 1546 dateSeparator, 1547 timeSeparator, 1548 decimalSymbols.getCurrencySymbol(), 1549 currencyFormatString, 1550 dateSymbols.getShortWeekdays(), 1551 dateSymbols.getWeekdays(), 1552 dateSymbols.getShortMonths(), 1553 dateSymbols.getMonths(), 1554 locale); 1555 } 1556 1557 private static void appendTimes(StringBuilder buf, char c, int i) { 1558 while (i-- > 0) { 1559 buf.append(c); 1560 } 1561 } 1562 1563 1567 public static FormatLocale getFormatLocale(Locale locale) 1568 { 1569 if (locale == null) { 1570 locale = Locale.US; 1571 } 1572 String key = locale.toString(); 1573 return mapLocaleToFormatLocale.get(key); 1574 } 1575 1576 1580 public static synchronized FormatLocale getBestFormatLocale(Locale locale) 1581 { 1582 FormatLocale formatLocale; 1583 if (locale == null) { 1584 return locale_US; 1585 } 1586 String key = locale.toString(); 1587 formatLocale = mapLocaleToFormatLocale.get(key); 1589 if (formatLocale == null) { 1590 formatLocale = getFormatLocaleUsingFactory(locale); 1592 if (formatLocale == null) { 1593 formatLocale = locale_US; 1594 } 1595 mapLocaleToFormatLocale.put(key, formatLocale); 1597 } 1598 return formatLocale; 1599 } 1600 1601 private static FormatLocale getFormatLocaleUsingFactory(Locale locale) 1602 { 1603 FormatLocale formatLocale; 1604 if (!locale.getVariant().equals("")) { 1606 formatLocale = createLocale(locale); 1607 if (formatLocale != null) { 1608 return formatLocale; 1609 } 1610 locale = new Locale(locale.getLanguage(), locale.getCountry()); 1611 } 1612 if (!locale.getCountry().equals("")) { 1614 formatLocale = createLocale(locale); 1615 if (formatLocale != null) { 1616 return formatLocale; 1617 } 1618 locale = new Locale(locale.getLanguage()); 1619 } 1620 formatLocale = createLocale(locale); 1622 if (formatLocale != null) { 1623 return formatLocale; 1624 } 1625 return null; 1626 } 1627 1628 1632 public static FormatLocale registerFormatLocale( 1633 FormatLocale formatLocale, Locale locale) 1634 { 1635 String key = locale.toString(); FormatLocale previous = mapLocaleToFormatLocale.put(key, formatLocale); 1637 return previous; 1638 } 1639 1640 static final int NOT_IN_A_NUMBER = 0; 1642 static final int LEFT_OF_POINT = 1; 1643 static final int RIGHT_OF_POINT = 2; 1644 static final int RIGHT_OF_EXP = 3; 1645 1646 1651 private String parseFormatString( 1652 String formatString, List<BasicFormat> alternateFormatList) 1653 { 1654 int numberState = NOT_IN_A_NUMBER; 1656 StringBuilder ignored = new StringBuilder (); 1657 String prevIgnored = null; 1658 boolean haveSeenNumber = false; 1659 int digitsLeftOfPoint = 0, 1660 digitsRightOfPoint = 0, 1661 digitsRightOfExp = 0, 1662 zeroesLeftOfPoint = 0, 1663 zeroesRightOfPoint = 0, 1664 zeroesRightOfExp = 0; 1665 int stringCase = CASE_ASIS; 1666 boolean useDecimal = false, 1667 useThouSep = false, 1668 fillFromRight = true; 1669 1670 1673 int expFormat = FORMAT_NULL; 1674 1675 1677 for (int i = 0; i < macroTokens.length; i++) { 1679 if (formatString.equals(macroTokens[i].name)) { 1680 if (macroTokens[i].translation == null) { 1681 if (macroTokens[i].name.equals("Currency")) { 1683 formatString = locale.currencyFormat 1685 + ";(" +locale.currencyFormat + ")"; 1686 } else { 1687 throw new Error ( 1688 "Format: internal: token " + macroTokens[i].name + 1689 " should have translation"); 1690 } 1691 } else { 1692 formatString = macroTokens[i].translation; 1693 } 1694 break; 1695 } 1696 } 1697 1698 if (!formatString.endsWith(";")) { 1701 formatString = formatString + ";"; 1702 } 1703 1704 List<BasicFormat> formatList = new ArrayList<BasicFormat>(); 1706loop: 1707 while (formatString.length() > 0) { 1708 BasicFormat format = null; 1709 String newFormatString = null; 1710 boolean ignoreToken = false; 1711 for (int i = tokens.length - 1; i > 0; i--) { 1712 Token token = tokens[i]; 1713 if (formatString.startsWith(token.token)) { 1714 String matched = token.token; 1719 newFormatString = formatString.substring(matched.length()); 1720 if (token.isSpecial()) { 1721 switch (token.code) { 1722 case FORMAT_SEMI: 1723 formatString = newFormatString; 1724 break loop; 1725 1726 case FORMAT_POUND: 1727 switch (numberState) { 1728 case NOT_IN_A_NUMBER: 1729 numberState = LEFT_OF_POINT; 1730 case LEFT_OF_POINT: 1732 digitsLeftOfPoint++; 1733 break; 1734 case RIGHT_OF_POINT: 1735 digitsRightOfPoint++; 1736 break; 1737 case RIGHT_OF_EXP: 1738 digitsRightOfExp++; 1739 break; 1740 default: 1741 throw new Error (); 1742 } 1743 break; 1744 1745 case FORMAT_0: 1746 switch (numberState) { 1747 case NOT_IN_A_NUMBER: 1748 numberState = LEFT_OF_POINT; 1749 case LEFT_OF_POINT: 1751 zeroesLeftOfPoint++; 1752 break; 1753 case RIGHT_OF_POINT: 1754 zeroesRightOfPoint++; 1755 break; 1756 case RIGHT_OF_EXP: 1757 zeroesRightOfExp++; 1758 break; 1759 default: 1760 throw new Error (); 1761 } 1762 break; 1763 1764 case FORMAT_M: 1765 case FORMAT_MM: 1766 { 1767 boolean theyMeantMinute = false; 1770 int j = formatList.size() - 1; 1771 while (j >= 0) { 1772 BasicFormat prevFormat = formatList.get(j); 1773 if (prevFormat instanceof LiteralFormat) { 1774 j--; 1776 } else if (prevFormat.code == FORMAT_H || 1777 prevFormat.code == FORMAT_HH) { 1778 theyMeantMinute = true; 1779 break; 1780 } else { 1781 theyMeantMinute = false; 1782 break; 1783 } 1784 } 1785 if (theyMeantMinute) { 1786 format = new DateFormat( 1787 (token.code == FORMAT_M 1788 ? FORMAT_N 1789 : FORMAT_NN), 1790 matched, 1791 locale, 1792 false); 1793 } else { 1794 format = token.makeFormat(locale); 1795 } 1796 break; 1797 } 1798 1799 case FORMAT_DECIMAL: 1800 { 1801 numberState = RIGHT_OF_POINT; 1802 useDecimal = true; 1803 break; 1804 } 1805 1806 case FORMAT_THOUSEP: 1807 { 1808 if (numberState == LEFT_OF_POINT) { 1809 useThouSep = true; 1811 } else { 1812 format = token.makeFormat(locale); 1814 } 1815 break; 1816 } 1817 1818 case FORMAT_TIMESEP: 1819 { 1820 format = new LiteralFormat(locale.timeSeparator); 1821 break; 1822 } 1823 1824 case FORMAT_DATESEP: 1825 { 1826 format = new LiteralFormat(locale.dateSeparator); 1827 break; 1828 } 1829 1830 case FORMAT_BACKSLASH: 1831 { 1832 String s = ""; 1834 if (formatString.length() == 1) { 1835 s = ""; 1838 newFormatString = ""; 1839 } else { 1840 s = formatString.substring(1,2); 1841 newFormatString = formatString.substring(2); 1842 } 1843 format = new LiteralFormat(s); 1844 break; 1845 } 1846 1847 case FORMAT_E_MINUS_UPPER: 1848 case FORMAT_E_PLUS_UPPER: 1849 case FORMAT_E_MINUS_LOWER: 1850 case FORMAT_E_PLUS_LOWER: 1851 { 1852 numberState = RIGHT_OF_EXP; 1853 expFormat = token.code; 1854 if (zeroesLeftOfPoint == 0 && 1855 zeroesRightOfPoint == 0) { 1856 zeroesLeftOfPoint = 1; 1859 } 1860 break; 1861 } 1862 1863 case FORMAT_QUOTE: 1864 { 1865 String s; 1868 int j = formatString.indexOf("\"", 1); 1869 if (j == -1) { 1870 s = formatString.substring(1); 1873 newFormatString = ""; 1874 } else { 1875 s = formatString.substring(1, j); 1877 newFormatString = formatString.substring( 1878 j + 1); 1879 } 1880 format = new LiteralFormat(s); 1881 break; 1882 } 1883 1884 case FORMAT_UPPER: 1885 { 1886 stringCase = CASE_UPPER; 1887 break; 1888 } 1889 1890 case FORMAT_LOWER: 1891 { 1892 stringCase = CASE_LOWER; 1893 break; 1894 } 1895 1896 case FORMAT_FILL_FROM_LEFT: 1897 { 1898 fillFromRight = false; 1899 break; 1900 } 1901 1902 case FORMAT_GENERAL_NUMBER: 1903 { 1904 format = new JavaFormat(locale.locale); 1905 break; 1906 } 1907 1908 case FORMAT_GENERAL_DATE: 1909 { 1910 format = new JavaFormat(locale.locale); 1911 break; 1912 } 1913 1914 case FORMAT_INTL_CURRENCY: 1915 { 1916 format = new LiteralFormat(locale.currencySymbol); 1917 break; 1918 } 1919 1920 default: 1921 throw new Error (); 1922 } 1923 if (format == null) { 1924 ignoreToken = true; 1928 ignored.append(matched); 1929 } else { 1930 prevIgnored = ignored.toString(); 1931 ignored.setLength(0); 1932 } 1933 } else { 1934 format = token.makeFormat(locale); 1935 } 1936 break; 1937 } 1938 } 1939 1940 if (format == null && !ignoreToken) { 1941 format = new LiteralFormat( 1944 formatString.substring(0,1)); 1945 newFormatString = formatString.substring(1); 1946 } 1947 1948 if (format != null) { 1949 if (numberState != NOT_IN_A_NUMBER) { 1950 NumericFormat numericFormat = new NumericFormat( 1953 prevIgnored, locale, expFormat, digitsLeftOfPoint, 1954 zeroesLeftOfPoint, digitsRightOfPoint, 1955 zeroesRightOfPoint, digitsRightOfExp, zeroesRightOfExp, 1956 useDecimal, useThouSep); 1957 formatList.add(numericFormat); 1958 numberState = NOT_IN_A_NUMBER; 1959 haveSeenNumber = true; 1960 } 1961 1962 formatList.add(format); 1963 } 1964 1965 formatString = newFormatString; 1966 } 1967 1968 if (numberState != NOT_IN_A_NUMBER) { 1969 NumericFormat numericFormat = new NumericFormat( 1971 prevIgnored, locale, expFormat, digitsLeftOfPoint, 1972 zeroesLeftOfPoint, digitsRightOfPoint, zeroesRightOfPoint, 1973 digitsRightOfExp, zeroesRightOfExp, useDecimal, useThouSep); 1974 formatList.add(numericFormat); 1975 numberState = NOT_IN_A_NUMBER; 1976 haveSeenNumber = true; 1977 } 1978 1979 BasicFormat[] formats = 1982 formatList.toArray(new BasicFormat[formatList.size()]); 1983 1984 boolean twelveHourClock = false; 1988 int decimalShift = 0; 1989 for (int i = 0; i < formats.length; i++) { 1990 switch (formats[i].code) { 1991 case FORMAT_UPPER_AM_SOLIDUS_PM: 1992 case FORMAT_LOWER_AM_SOLIDUS_PM: 1993 case FORMAT_UPPER_A_SOLIDUS_P: 1994 case FORMAT_LOWER_A_SOLIDUS_P: 1995 case FORMAT_AMPM: 1996 twelveHourClock = true; 1997 break; 1998 1999 case FORMAT_PERCENT: 2000 decimalShift += 2; 2002 break; 2003 2004 case FORMAT_THOUSEP: 2005 if (haveSeenNumber && 2009 i + 1 < formats.length && 2010 formats[i + 1].code != FORMAT_THOUSEP && 2011 formats[i + 1].code != FORMAT_0 && 2012 formats[i + 1].code != FORMAT_POUND) { 2013 for (int j = i; 2014 j >= 0 && formats[j].code == FORMAT_THOUSEP; 2015 j--) { 2016 decimalShift -= 3; 2017 formats[j] = new LiteralFormat(""); } 2019 } 2020 break; 2021 2022 default: 2023 } 2024 } 2025 2026 if (twelveHourClock) { 2027 for (int i = 0; i < formats.length; i++) { 2028 if (formats[i] instanceof DateFormat) { 2029 ((DateFormat) formats[i]).setTwelveHourClock(true); 2030 } 2031 } 2032 } 2033 2034 if (decimalShift != 0) { 2035 for (int i = 0; i < formats.length; i++) { 2036 if (formats[i] instanceof NumericFormat) { 2037 ((NumericFormat) formats[i]).decimalShift = decimalShift; 2038 } 2039 } 2040 } 2041 2042 BasicFormat alternateFormat = 2044 formats.length == 0 ? null : 2045 formats.length == 1 ? formats[0] : 2046 new CompoundFormat(formats); 2047 alternateFormatList.add(alternateFormat); 2048 return formatString; 2049 } 2050 2051 public String format(Object o) 2052 { 2053 StringBuilder buf = new StringBuilder (); 2054 format(o, buf); 2055 return buf.toString(); 2056 } 2057 2058 private StringBuilder format(Object o, StringBuilder buf) { 2059 if (o == null) { 2060 format.formatNull(buf); 2061 } else { 2062 Class <? extends Object > clazz = o.getClass(); 2065 if (clazz == Double .class) { 2066 format.format(((Double ) o).doubleValue(), buf); 2067 } else if (clazz == Float .class) { 2068 format.format(((Float ) o).floatValue(), buf); 2069 } else if (clazz == Integer .class) { 2070 format.format(((Integer ) o).intValue(), buf); 2071 } else if (clazz == Long .class) { 2072 format.format(((Long ) o).longValue(), buf); 2073 } else if (clazz == Short .class) { 2074 format.format(((Short ) o).shortValue(), buf); 2075 } else if (clazz == Byte .class) { 2076 format.format(((Byte ) o).byteValue(), buf); 2077 } else if (o instanceof BigDecimal ) { 2078 format.format(((BigDecimal ) o).doubleValue(), buf); 2079 } else if (o instanceof BigInteger ) { 2080 format.format(((BigInteger ) o).longValue(), buf); 2081 } else if (clazz == String .class) { 2082 format.format((String ) o, buf); 2083 } else if (o instanceof java.util.Date ) { 2084 format.format((Date) o, buf); 2086 } else { 2087 buf.append(o.toString()); 2088 } 2089 } 2090 return buf; 2091 } 2092 2093 public String getFormatString() 2094 { 2095 return formatString; 2096 } 2097 2098 2101 public interface LocaleFormatFactory { 2102 FormatLocale get(Locale locale); 2103 } 2104 2105 2108static class FloatingDecimal { 2109 boolean isExceptional; 2110 boolean isNegative; 2111 int decExponent; 2112 char digits[]; 2113 int nDigits; 2114 2115 2120 static final long signMask = 0x8000000000000000L; 2121 static final long expMask = 0x7ff0000000000000L; 2122 static final long fractMask= ~(signMask|expMask); 2123 static final int expShift = 52; 2124 static final int expBias = 1023; 2125 static final long fractHOB = ( 1L<<expShift ); static final long expOne = ((long)expBias)<<expShift; static final int maxSmallBinExp = 62; 2128 static final int minSmallBinExp = -( 63 / 3 ); 2129 2130 static final long highbyte = 0xff00000000000000L; 2131 static final long highbit = 0x8000000000000000L; 2132 static final long lowbytes = ~highbyte; 2133 2134 static final int singleSignMask = 0x80000000; 2135 static final int singleExpMask = 0x7f800000; 2136 static final int singleFractMask = ~(singleSignMask|singleExpMask); 2137 static final int singleExpShift = 23; 2138 static final int singleFractHOB = 1<<singleExpShift; 2139 static final int singleExpBias = 127; 2140 2141 2145 private static int 2146 countBits( long v ){ 2147 if ( v == 0L ) return 0; 2153 2154 while ( ( v & highbyte ) == 0L ){ 2155 v <<= 8; 2156 } 2157 while ( v > 0L ) { v <<= 1; 2159 } 2160 2161 int n = 0; 2162 while (( v & lowbytes ) != 0L ){ 2163 v <<= 8; 2164 n += 8; 2165 } 2166 while ( v != 0L ){ 2167 v <<= 1; 2168 n += 1; 2169 } 2170 return n; 2171 } 2172 2173 2176 private static FDBigInt b5p[]; 2177 2178 private static FDBigInt 2179 big5pow( int p ){ 2180 if ( p < 0 ) 2181 throw new RuntimeException ( "Assertion botch: negative power of 5"); 2182 if ( b5p == null ){ 2183 b5p = new FDBigInt[ p+1 ]; 2184 }else if (b5p.length <= p ){ 2185 FDBigInt t[] = new FDBigInt[ p+1 ]; 2186 System.arraycopy( b5p, 0, t, 0, b5p.length ); 2187 b5p = t; 2188 } 2189 if ( b5p[p] != null ) 2190 return b5p[p]; 2191 else if ( p < small5pow.length ) 2192 return b5p[p] = new FDBigInt( small5pow[p] ); 2193 else if ( p < long5pow.length ) 2194 return b5p[p] = new FDBigInt( long5pow[p] ); 2195 else { 2196 int q, r; 2199 q = p >> 1; 2204 r = p - q; 2205 FDBigInt bigq = b5p[q]; 2206 if ( bigq == null ) 2207 bigq = big5pow ( q ); 2208 if ( r < small5pow.length ){ 2209 return (b5p[p] = bigq.mult( small5pow[r] ) ); 2210 }else{ 2211 FDBigInt bigr = b5p[ r ]; 2212 if ( bigr == null ) 2213 bigr = big5pow( r ); 2214 return (b5p[p] = bigq.mult( bigr ) ); 2215 } 2216 } 2217 } 2218 2219 2234 private void 2235 developLongDigits( int decExponent, long lvalue, long insignificant ){ 2236 char digits[]; 2237 int ndigits; 2238 int digitno; 2239 int c; 2240 int i; 2244 for ( i = 0; insignificant >= 10L; i++ ) 2245 insignificant /= 10L; 2246 if ( i != 0 ){ 2247 long pow10 = long5pow[i] << i; long residue = lvalue % pow10; 2249 lvalue /= pow10; 2250 decExponent += i; 2251 if ( residue >= (pow10>>1) ){ 2252 lvalue++; 2254 } 2255 } 2256 if ( lvalue <= Integer.MAX_VALUE ){ 2257 if ( lvalue <= 0L ) 2258 throw new RuntimeException ("Assertion botch: value "+lvalue+" <= 0"); 2259 2260 int ivalue = (int)lvalue; 2263 digits = new char[ ndigits=10 ]; 2264 digitno = ndigits-1; 2265 c = ivalue%10; 2266 ivalue /= 10; 2267 while ( c == 0 ){ 2268 decExponent++; 2269 c = ivalue%10; 2270 ivalue /= 10; 2271 } 2272 while ( ivalue != 0){ 2273 digits[digitno--] = (char)(c+'0'); 2274 decExponent++; 2275 c = ivalue%10; 2276 ivalue /= 10; 2277 } 2278 digits[digitno] = (char)(c+'0'); 2279 } else { 2280 digits = new char[ ndigits=20 ]; 2283 digitno = ndigits-1; 2284 c = (int)(lvalue%10L); 2285 lvalue /= 10L; 2286 while ( c == 0 ){ 2287 decExponent++; 2288 c = (int)(lvalue%10L); 2289 lvalue /= 10L; 2290 } 2291 while ( lvalue != 0L ){ 2292 digits[digitno--] = (char)(c+'0'); 2293 decExponent++; 2294 c = (int)(lvalue%10L); 2295 lvalue /= 10; 2296 } 2297 digits[digitno] = (char)(c+'0'); 2298 } 2299 char result []; 2300 ndigits -= digitno; 2301 if ( digitno == 0 ) 2302 result = digits; 2303 else { 2304 result = new char[ ndigits ]; 2305 System.arraycopy( digits, digitno, result, 0, ndigits ); 2306 } 2307 this.digits = result; 2308 this.decExponent = decExponent+1; 2309 this.nDigits = ndigits; 2310 } 2311 2312 private void 2320 roundup(){ 2321 int i; 2322 int q = digits[ i = (nDigits-1)]; 2323 if ( q == '9' ){ 2324 while ( q == '9' && i > 0 ){ 2325 digits[i] = '0'; 2326 q = digits[--i]; 2327 } 2328 if ( q == '9' ){ 2329 decExponent += 1; 2331 digits[0] = '1'; 2332 return; 2333 } 2334 } 2336 digits[i] = (char)(q+1); 2337 } 2338 2339 2342 public FloatingDecimal( double d ) 2343 { 2344 long dBits = Double.doubleToLongBits( d ); 2345 long fractBits; 2346 int binExp; 2347 int nSignificantBits; 2348 2349 if ( (dBits&signMask) != 0 ){ 2351 isNegative = true; 2352 dBits ^= signMask; 2353 } else { 2354 isNegative = false; 2355 } 2356 binExp = (int)( (dBits&expMask) >> expShift ); 2359 fractBits = dBits&fractMask; 2360 if ( binExp == (int)(expMask>>expShift) ) { 2361 isExceptional = true; 2362 if ( fractBits == 0L ){ 2363 digits = infinity; 2364 } else { 2365 digits = notANumber; 2366 isNegative = false; } 2368 nDigits = digits.length; 2369 return; 2370 } 2371 isExceptional = false; 2372 if ( binExp == 0 ){ 2377 if ( fractBits == 0L ){ 2378 decExponent = 0; 2380 digits = zero; 2381 nDigits = 1; 2382 return; 2383 } 2384 while ( (fractBits&fractHOB) == 0L ){ 2385 fractBits <<= 1; 2386 binExp -= 1; 2387 } 2388 nSignificantBits = expShift + binExp; binExp += 1; 2390 } else { 2391 fractBits |= fractHOB; 2392 nSignificantBits = expShift+1; 2393 } 2394 binExp -= expBias; 2395 dtoa( binExp, fractBits, nSignificantBits ); 2397 } 2398 2399 2402 public FloatingDecimal( float f ) 2403 { 2404 int fBits = Float.floatToIntBits( f ); 2405 int fractBits; 2406 int binExp; 2407 int nSignificantBits; 2408 2409 if ( (fBits&singleSignMask) != 0 ){ 2411 isNegative = true; 2412 fBits ^= singleSignMask; 2413 } else { 2414 isNegative = false; 2415 } 2416 binExp = ( (fBits&singleExpMask) >> singleExpShift ); 2419 fractBits = fBits&singleFractMask; 2420 if ( binExp == (singleExpMask>>singleExpShift) ) { 2421 isExceptional = true; 2422 if ( fractBits == 0L ){ 2423 digits = infinity; 2424 } else { 2425 digits = notANumber; 2426 isNegative = false; } 2428 nDigits = digits.length; 2429 return; 2430 } 2431 isExceptional = false; 2432 if ( binExp == 0 ){ 2437 if ( fractBits == 0 ){ 2438 decExponent = 0; 2440 digits = zero; 2441 nDigits = 1; 2442 return; 2443 } 2444 while ( (fractBits&singleFractHOB) == 0 ){ 2445 fractBits <<= 1; 2446 binExp -= 1; 2447 } 2448 nSignificantBits = singleExpShift + binExp; binExp += 1; 2450 } else { 2451 fractBits |= singleFractHOB; 2452 nSignificantBits = singleExpShift+1; 2453 } 2454 binExp -= singleExpBias; 2455 dtoa( binExp, ((long)fractBits)<<(expShift-singleExpShift), nSignificantBits ); 2457 } 2458 2459 private void 2460 dtoa( int binExp, long fractBits, int nSignificantBits ) 2461 { 2462 int nFractBits; int nTinyBits; int decExp; 2465 2466 nFractBits = countBits( fractBits ); 2470 nTinyBits = Math.max( 0, nFractBits - binExp - 1 ); 2471 if ( binExp <= maxSmallBinExp && binExp >= minSmallBinExp ){ 2472 if ( (nTinyBits < long5pow.length) && ((nFractBits + n5bits[nTinyBits]) < 64 ) ){ 2476 2491 long halfULP; 2492 if ( nTinyBits == 0 ) { 2493 if ( binExp > nSignificantBits ){ 2494 halfULP = 1L << ( binExp-nSignificantBits-1); 2495 } else { 2496 halfULP = 0L; 2497 } 2498 if ( binExp >= expShift ){ 2499 fractBits <<= (binExp-expShift); 2500 } else { 2501 fractBits >>>= (expShift-binExp) ; 2502 } 2503 developLongDigits( 0, fractBits, halfULP ); 2504 return; 2505 } 2506 2521 } 2522 } 2523 2542 2543 2555 double d2 = Double.longBitsToDouble( 2556 expOne | ( fractBits &~ fractHOB ) ); 2557 decExp = (int)Math.floor( 2558 (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981 ); 2559 int B2, B5; int S2, S5; int M2, M5; int Bbits; int tenSbits; FDBigInt Sval, Bval, Mval; 2565 2566 B5 = Math.max( 0, -decExp ); 2567 B2 = B5 + nTinyBits + binExp; 2568 2569 S5 = Math.max( 0, decExp ); 2570 S2 = S5 + nTinyBits; 2571 2572 M5 = B5; 2573 M2 = B2 - nSignificantBits; 2574 2575 2583 fractBits >>>= (expShift+1-nFractBits); 2584 B2 -= nFractBits-1; 2585 int common2factor = Math.min( B2, S2 ); 2586 B2 -= common2factor; 2587 S2 -= common2factor; 2588 M2 -= common2factor; 2589 2590 2596 if ( nFractBits == 1 ) 2597 M2 -= 1; 2598 2599 if ( M2 < 0 ){ 2600 B2 -= M2; 2604 S2 -= M2; 2605 M2 = 0; 2606 } 2607 2615 char digits[] = this.digits = new char[18]; 2616 int ndigit = 0; 2617 boolean low, high; 2618 long lowDigitDifference; 2619 int q; 2620 2621 2636 Bbits = nFractBits + B2 + (( B5 < n5bits.length )? n5bits[B5] : ( B5*3 )); 2637 tenSbits = S2+1 + (( (S5+1) < n5bits.length )? n5bits[(S5+1)] : ( (S5+1)*3 )); 2638 if ( Bbits < 64 && tenSbits < 64){ 2639 if ( Bbits < 32 && tenSbits < 32){ 2640 int b = ((int)fractBits * small5pow[B5] ) << B2; 2642 int s = small5pow[S5] << S2; 2643 int m = small5pow[M5] << M2; 2644 int tens = s * 10; 2645 2650 ndigit = 0; 2651 q = ( b / s ); 2652 b = 10 * ( b % s ); 2653 m *= 10; 2654 low = (b < m ); 2655 high = (b+m > tens ); 2656 if ( q >= 10 ){ 2657 throw new RuntimeException ( "Assertion botch: excessivly large digit "+q); 2659 } else if ( (q == 0) && ! high ){ 2660 decExp--; 2662 } else { 2663 digits[ndigit++] = (char)('0' + q); 2664 } 2665 2671 if ( decExp <= -3 || decExp >= 8 ){ 2672 high = low = false; 2673 } 2674 while( ! low && ! high ){ 2675 q = ( b / s ); 2676 b = 10 * ( b % s ); 2677 m *= 10; 2678 if ( q >= 10 ){ 2679 throw new RuntimeException ( "Assertion botch: excessivly large digit "+q); 2681 } 2682 if ( m > 0L ){ 2683 low = (b < m ); 2684 high = (b+m > tens ); 2685 } else { 2686 low = true; 2692 high = true; 2693 } 2694 digits[ndigit++] = (char)('0' + q); 2695 } 2696 lowDigitDifference = (b<<1) - tens; 2697 } else { 2698 long b = (fractBits * long5pow[B5] ) << B2; 2700 long s = long5pow[S5] << S2; 2701 long m = long5pow[M5] << M2; 2702 long tens = s * 10L; 2703 2708 ndigit = 0; 2709 q = (int) ( b / s ); 2710 b = 10L * ( b % s ); 2711 m *= 10L; 2712 low = (b < m ); 2713 high = (b+m > tens ); 2714 if ( q >= 10 ){ 2715 throw new RuntimeException ( "Assertion botch: excessivly large digit "+q); 2717 } else if ( (q == 0) && ! high ){ 2718 decExp--; 2720 } else { 2721 digits[ndigit++] = (char)('0' + q); 2722 } 2723 2729 if ( decExp <= -3 || decExp >= 8 ){ 2730 high = low = false; 2731 } 2732 while( ! low && ! high ){ 2733 q = (int) ( b / s ); 2734 b = 10 * ( b % s ); 2735 m *= 10; 2736 if ( q >= 10 ){ 2737 throw new RuntimeException ( "Assertion botch: excessivly large digit "+q); 2739 } 2740 if ( m > 0L ){ 2741 low = (b < m ); 2742 high = (b+m > tens ); 2743 } else { 2744 low = true; 2750 high = true; 2751 } 2752 digits[ndigit++] = (char)('0' + q); 2753 } 2754 lowDigitDifference = (b<<1) - tens; 2755 } 2756 } else { 2757 FDBigInt tenSval; 2758 int shiftBias; 2759 2760 2764 Bval = new FDBigInt( fractBits ); 2765 if ( B5 != 0 ){ 2766 if ( B5 < small5pow.length ){ 2767 Bval = Bval.mult( small5pow[B5] ); 2768 } else { 2769 Bval = Bval.mult( big5pow( B5 ) ); 2770 } 2771 } 2772 if ( B2 != 0 ){ 2773 Bval.lshiftMe( B2 ); 2774 } 2775 Sval = new FDBigInt( big5pow( S5 ) ); 2776 if ( S2 != 0 ){ 2777 Sval.lshiftMe( S2 ); 2778 } 2779 Mval = new FDBigInt( big5pow( M5 ) ); 2780 if ( M2 != 0 ){ 2781 Mval.lshiftMe( M2 ); 2782 } 2783 2784 2785 Bval.lshiftMe( shiftBias = Sval.normalizeMe() ); 2787 Mval.lshiftMe( shiftBias ); 2788 tenSval = Sval.mult( 10 ); 2789 2794 ndigit = 0; 2795 q = Bval.quoRemIteration( Sval ); 2796 Mval = Mval.mult( 10 ); 2797 low = (Bval.cmp( Mval ) < 0); 2798 high = (Bval.add( Mval ).cmp( tenSval ) > 0 ); 2799 if ( q >= 10 ){ 2800 throw new RuntimeException ( "Assertion botch: excessivly large digit "+q); 2802 } else if ( (q == 0) && ! high ){ 2803 decExp--; 2805 } else { 2806 digits[ndigit++] = (char)('0' + q); 2807 } 2808 2814 if ( decExp <= -3 || decExp >= 8 ){ 2815 high = low = false; 2816 } 2817 while( ! low && ! high ){ 2818 q = Bval.quoRemIteration( Sval ); 2819 Mval = Mval.mult( 10 ); 2820 if ( q >= 10 ){ 2821 throw new RuntimeException ( "Assertion botch: excessivly large digit "+q); 2823 } 2824 low = (Bval.cmp( Mval ) < 0); 2825 high = (Bval.add( Mval ).cmp( tenSval ) > 0 ); 2826 digits[ndigit++] = (char)('0' + q); 2827 } 2828 if ( high && low ){ 2829 Bval.lshiftMe(1); 2830 lowDigitDifference = Bval.cmp(tenSval); 2831 } else 2832 lowDigitDifference = 0L; } 2834 this.decExponent = decExp+1; 2835 this.digits = digits; 2836 this.nDigits = ndigit; 2837 2840 if ( high ){ 2841 if ( low ){ 2842 if ( lowDigitDifference == 0L ){ 2843 if ( (digits[nDigits-1]&1) != 0 ) roundup(); 2846 } else if ( lowDigitDifference > 0 ){ 2847 roundup(); 2848 } 2849 } else { 2850 roundup(); 2851 } 2852 } 2853 } 2854 2855 public String 2856 toString(){ 2857 StringBuilder result = new StringBuilder ( nDigits+8 ); 2859 if ( isNegative ){ result.append( '-' ); } 2860 if ( isExceptional ){ 2861 result.append( digits, 0, nDigits ); 2862 } else { 2863 result.append( "0."); 2864 result.append( digits, 0, nDigits ); 2865 result.append('e'); 2866 result.append( decExponent ); 2867 } 2868 return new String (result); 2869 } 2870 2871 public String 2872 toJavaFormatString(){ 2873 char result[] = new char[ nDigits + 10 ]; 2874 int i = 0; 2875 if ( isNegative ){ result[0] = '-'; i = 1; } 2876 if ( isExceptional ){ 2877 System.arraycopy( digits, 0, result, i, nDigits ); 2878 i += nDigits; 2879 } else { 2880 if ( decExponent > 0 && decExponent < 8 ){ 2881 int charLength = Math.min( nDigits, decExponent ); 2883 System.arraycopy( digits, 0, result, i, charLength ); 2884 i += charLength; 2885 if ( charLength < decExponent ){ 2886 charLength = decExponent-charLength; 2887 System.arraycopy( zero, 0, result, i, charLength ); 2888 i += charLength; 2889 result[i++] = '.'; 2890 result[i++] = '0'; 2891 } else { 2892 result[i++] = '.'; 2893 if ( charLength < nDigits ){ 2894 int t = nDigits - charLength; 2895 System.arraycopy( digits, charLength, result, i, t ); 2896 i += t; 2897 } else{ 2898 result[i++] = '0'; 2899 } 2900 } 2901 } else if ( decExponent <=0 && decExponent > -3 ){ 2902 result[i++] = '0'; 2903 result[i++] = '.'; 2904 if ( decExponent != 0 ){ 2905 System.arraycopy( zero, 0, result, i, -decExponent ); 2906 i -= decExponent; 2907 } 2908 System.arraycopy( digits, 0, result, i, nDigits ); 2909 i += nDigits; 2910 } else { 2911 result[i++] = digits[0]; 2912 result[i++] = '.'; 2913 if ( nDigits > 1 ){ 2914 System.arraycopy( digits, 1, result, i, nDigits-1 ); 2915 i += nDigits-1; 2916 } else { 2917 result[i++] = '0'; 2918 } 2919 result[i++] = 'E'; 2920 int e; 2921 if ( decExponent <= 0 ){ 2922 result[i++] = '-'; 2923 e = -decExponent+1; 2924 } else { 2925 e = decExponent-1; 2926 } 2927 if ( e <= 9 ) { 2929 result[i++] = (char)( e+'0' ); 2930 } else if ( e <= 99 ){ 2931 result[i++] = (char)( e/10 +'0' ); 2932 result[i++] = (char)( e%10 + '0' ); 2933 } else { 2934 result[i++] = (char)(e/100+'0'); 2935 e %= 100; 2936 result[i++] = (char)(e/10+'0'); 2937 result[i++] = (char)( e%10 + '0' ); 2938 } 2939 } 2940 } 2941 return new String (result, 0, i); 2942 } 2943 2944 public FloatingDecimal(long n) 2946 { 2947 isExceptional = false; if (n < 0) { 2949 isNegative = true; 2950 n = -n; } else { 2952 isNegative = false; 2953 } 2954 if (n == 0) { 2955 nDigits = 1; 2956 digits = new char[] {'0','0','0','0','0','0','0','0'}; 2957 decExponent = 0; 2958 } else { 2959 nDigits = 0; 2960 for (long m = n; m != 0; m = m / 10) { 2961 nDigits++; 2962 } 2963 decExponent = nDigits; 2964 digits = new char[nDigits]; 2965 int i = nDigits - 1; 2966 for (long m = n; m != 0; m = m / 10) { 2967 digits[i--] = (char) ('0' + (m % 10)); 2968 } 2969 } 2970 } 2971 2972 public void shift(int i) 2974 { 2975 if (isExceptional || 2976 nDigits == 1 && digits[0] == '0') { 2977 ; } else { 2979 decExponent += i; 2980 } 2981 } 2982 2983 public String toJavaFormatString( 2985 int minDigitsLeftOfDecimal, 2986 char decimalChar, int minDigitsRightOfDecimal, 2988 int maxDigitsRightOfDecimal, char expChar, boolean expSign, int minExpDigits, char thousandChar) { 2994 int resultLen = 10 + Math.abs(decExponent)*4/3 + maxDigitsRightOfDecimal; 3001 char result[] = new char[resultLen]; 3002 int i = toJavaFormatString( 3003 result, 0, minDigitsLeftOfDecimal, decimalChar, 3004 minDigitsRightOfDecimal, maxDigitsRightOfDecimal, expChar, expSign, 3005 minExpDigits, thousandChar); 3006 return new String (result, 0, i); 3007 } 3008 3009 private synchronized int toJavaFormatString( 3011 char result[], 3012 int i, 3013 int minDigitsLeftOfDecimal, 3014 char decimalChar, int minDigitsRightOfDecimal, 3016 int maxDigitsRightOfDecimal, char expChar, boolean expSign, int minExpDigits, char thousandChar) { 3022 if (isNegative) { 3023 result[i++] = '-'; 3024 } 3025 if (isExceptional) { 3026 System.arraycopy(digits, 0, result, i, nDigits); 3027 i += nDigits; 3028 } else if (expChar == 0) { 3029 int wholeDigits = Math.max(decExponent, minDigitsLeftOfDecimal), 3041 fractionDigits = Math.max( 3042 nDigits - decExponent, minDigitsRightOfDecimal), 3043 totalDigits = wholeDigits + fractionDigits; 3044 char[] digits2 = new char[totalDigits]; 3045 for (int j = 0; j < totalDigits; j++) { 3046 digits2[j] = '0'; 3047 } 3048 for (int j = 0; j < nDigits; j++) { 3049 digits2[wholeDigits - decExponent + j] = digits[j]; 3050 } 3051 3052 int lastDigit = wholeDigits + maxDigitsRightOfDecimal; 3061 if (lastDigit < totalDigits) { 3062 boolean trailingZeroes = true; 3065 int m = totalDigits; 3066 while (true) { 3067 m--; 3068 if (m < 0) { 3069 wholeDigits++; 3072 totalDigits++; 3073 lastDigit++; 3074 char[] old = digits2; 3075 digits2 = new char[totalDigits]; 3076 digits2[0] = '1'; 3077 System.arraycopy(old, 0, digits2, 1, old.length); 3078 break; 3079 } else if (m == lastDigit) { 3080 char d = digits2[m]; 3081 digits2[m] = '0'; 3082 if (d < '5' || 3083 d == '5' && trailingZeroes) { 3084 break; } 3086 } else if (m > lastDigit) { 3087 if (digits2[m] > '0') { 3088 trailingZeroes = false; 3089 } 3090 digits2[m] = '0'; 3091 } else if (digits2[m] == '9') { 3092 digits2[m] = '0'; 3093 } else { 3095 digits2[m]++; 3096 break; } 3098 } 3099 } 3100 3101 int firstNonZero = wholeDigits, 3103 firstTrailingZero = 0; 3104 for (int j = 0; j < totalDigits; j++) { 3105 if (digits2[j] != '0') { 3106 if (j < firstNonZero) { 3107 firstNonZero = j; 3108 } 3109 firstTrailingZero = j + 1; 3110 } 3111 } 3112 3113 int firstDigitToPrint = firstNonZero; 3114 if (firstDigitToPrint > wholeDigits - minDigitsLeftOfDecimal) { 3115 firstDigitToPrint = wholeDigits - minDigitsLeftOfDecimal; 3116 } 3117 int lastDigitToPrint = firstTrailingZero; 3118 if (lastDigitToPrint > wholeDigits + maxDigitsRightOfDecimal) { 3119 lastDigitToPrint = wholeDigits + maxDigitsRightOfDecimal; 3120 } 3121 if (lastDigitToPrint < wholeDigits + minDigitsRightOfDecimal) { 3122 lastDigitToPrint = wholeDigits + minDigitsRightOfDecimal; 3123 } 3124 3125 for (int j = firstDigitToPrint; j < wholeDigits; j++) { 3127 if (thousandChar != '\0' && 3128 (wholeDigits - j) % 3 == 0 && 3129 j > firstDigitToPrint && 3130 j < wholeDigits - 1) { 3131 result[i++] = thousandChar; 3132 } 3133 result[i++] = digits2[j]; 3134 } 3135 for (int j = wholeDigits; j < lastDigitToPrint; j++) { 3136 if (j == wholeDigits) { 3137 result[i++] = decimalChar; 3138 } 3139 result[i++] = digits2[j]; 3140 } 3141 } else { 3142 int oldExp = decExponent; 3144 decExponent = Math.min(minDigitsLeftOfDecimal, nDigits); 3145 boolean oldIsNegative = isNegative; 3146 isNegative = false; 3147 i = toJavaFormatString( 3148 result, i, minDigitsLeftOfDecimal, decimalChar, 3149 minDigitsRightOfDecimal, maxDigitsRightOfDecimal, (char) 0, 3150 false, minExpDigits, '\0'); 3151 decExponent = oldExp; 3152 isNegative = oldIsNegative; 3153 3154 result[i++] = expChar; 3155 int de = decExponent; 3156 if (nDigits == 1 && digits[0] == '0') { 3157 de = 1; } 3159 int e; 3160 if ( de <= 0 ){ 3161 result[i++] = '-'; 3162 e = -de+1; 3163 } else { 3164 if (expSign) { 3165 result[i++] = '+'; 3166 } 3167 e = de-1; 3168 } 3169 int nExpDigits = e <= 9 ? 1 : e <= 99 ? 2 : 3; 3171 for (int j = nExpDigits; j < minExpDigits; j++) { 3172 result[i++] = '0'; 3173 } 3174 if ( e <= 9 ) { 3175 result[i++] = (char)( e+'0' ); 3176 } else if ( e <= 99 ){ 3177 result[i++] = (char)( e/10 +'0' ); 3178 result[i++] = (char)( e%10 + '0' ); 3179 } else { 3180 result[i++] = (char)(e/100+'0'); 3181 e %= 100; 3182 result[i++] = (char)(e/10+'0'); 3183 result[i++] = (char)( e%10 + '0' ); 3184 } 3185 } 3186 return i; 3187 } 3188 3189 private static final int small5pow[] = { 3190 1, 3191 5, 3192 5*5, 3193 5*5*5, 3194 5*5*5*5, 3195 5*5*5*5*5, 3196 5*5*5*5*5*5, 3197 5*5*5*5*5*5*5, 3198 5*5*5*5*5*5*5*5, 3199 5*5*5*5*5*5*5*5*5, 3200 5*5*5*5*5*5*5*5*5*5, 3201 5*5*5*5*5*5*5*5*5*5*5, 3202 5*5*5*5*5*5*5*5*5*5*5*5, 3203 5*5*5*5*5*5*5*5*5*5*5*5*5 3204 }; 3205 3206 private static final long long5pow[] = { 3207 1L, 3208 5L, 3209 5L*5, 3210 5L*5*5, 3211 5L*5*5*5, 3212 5L*5*5*5*5, 3213 5L*5*5*5*5*5, 3214 5L*5*5*5*5*5*5, 3215 5L*5*5*5*5*5*5*5, 3216 5L*5*5*5*5*5*5*5*5, 3217 5L*5*5*5*5*5*5*5*5*5, 3218 5L*5*5*5*5*5*5*5*5*5*5, 3219 5L*5*5*5*5*5*5*5*5*5*5*5, 3220 5L*5*5*5*5*5*5*5*5*5*5*5*5, 3221 5L*5*5*5*5*5*5*5*5*5*5*5*5*5, 3222 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3223 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3224 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3225 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3226 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3227 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3228 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3229 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3230 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3231 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3232 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3233 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5, 3234 }; 3235 3236 private static final int n5bits[] = { 3238 0, 3239 3, 3240 5, 3241 7, 3242 10, 3243 12, 3244 14, 3245 17, 3246 19, 3247 21, 3248 24, 3249 26, 3250 28, 3251 31, 3252 33, 3253 35, 3254 38, 3255 40, 3256 42, 3257 45, 3258 47, 3259 49, 3260 52, 3261 54, 3262 56, 3263 59, 3264 61, 3265 }; 3266 3267 private static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' }; 3268 private static final char notANumber[] = { 'N', 'a', 'N' }; 3269 private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' }; 3270} 3271 3272 3276static class FDBigInt { 3277 int nWords; int data[]; 3280 private static boolean debugging = false; 3281 3282 public static void setDebugging( boolean d ) { debugging = d; } 3283 3284 public FDBigInt( int v ){ 3285 nWords = 1; 3286 data = new int[1]; 3287 data[0] = v; 3288 } 3289 3290 public FDBigInt( long v ){ 3291 data = new int[2]; 3292 data[0] = (int)v; 3293 data[1] = (int)(v>>>32); 3294 nWords = (data[1]==0) ? 1 : 2; 3295 } 3296 3297 public FDBigInt( FDBigInt other ){ 3298 data = new int[nWords = other.nWords]; 3299 System.arraycopy( other.data, 0, data, 0, nWords ); 3300 } 3301 3302 private FDBigInt( int [] d, int n ){ 3303 data = d; 3304 nWords = n; 3305 } 3306 3307 3311 public void 3312 lshiftMe( int c )throws IllegalArgumentException { 3313 if ( c <= 0 ){ 3314 if ( c == 0 ) 3315 return; else 3317 throw new IllegalArgumentException ("negative shift count"); 3318 } 3319 int wordcount = c>>5; 3320 int bitcount = c & 0x1f; 3321 int anticount = 32-bitcount; 3322 int t[] = data; 3323 int s[] = data; 3324 if ( nWords+wordcount+1 > t.length ){ 3325 t = new int[ nWords+wordcount+1 ]; 3327 } 3328 int target = nWords+wordcount; 3329 int src = nWords-1; 3330 if ( bitcount == 0 ){ 3331 System.arraycopy( s, 0, t, wordcount, nWords ); 3333 target = wordcount-1; 3334 } else { 3335 t[target--] = s[src]>>>anticount; 3336 while ( src >= 1 ){ 3337 t[target--] = (s[src]<<bitcount) | (s[--src]>>>anticount); 3338 } 3339 t[target--] = s[src]<<bitcount; 3340 } 3341 while( target >= 0 ){ 3342 t[target--] = 0; 3343 } 3344 data = t; 3345 nWords += wordcount + 1; 3346 while ( nWords > 1 && data[nWords-1] == 0 ) 3349 nWords--; 3350 } 3351 3352 3363 public int 3364 normalizeMe() throws IllegalArgumentException { 3365 int src; 3366 int wordcount = 0; 3367 int bitcount = 0; 3368 int v = 0; 3369 for ( SRC= nWords-1 ; src >= 0 && (v=data[src]) == 0 ; src--){ 3370 wordcount += 1; 3371 } 3372 if ( src < 0 ){ 3373 throw new IllegalArgumentException ("zero value"); 3375 } 3376 3382 nWords -= wordcount; 3383 3388 if ( (v & 0xf0000000) != 0 ){ 3389 for( bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount-- ) 3392 v >>>= 1; 3393 } else { 3394 while ( v <= 0x000fffff ){ 3395 v <<= 8; 3397 bitcount += 8; 3398 } 3399 while ( v <= 0x07ffffff ){ 3400 v <<= 1; 3401 bitcount += 1; 3402 } 3403 } 3404 if ( bitcount != 0 ) 3405 lshiftMe( bitcount ); 3406 return bitcount; 3407 } 3408 3409 3413 public FDBigInt 3414 mult( int iv ) { 3415 long v = iv; 3416 int r[]; 3417 long p; 3418 3419 r = new int[ ( v * ((long)data[nWords-1]&0xffffffffL) > 0xfffffffL ) ? nWords+1 : nWords ]; 3421 p = 0L; 3422 for( int i=0; i < nWords; i++ ) { 3423 p += v * ((long)data[i]&0xffffffffL); 3424 r[i] = (int)p; 3425 p >>>= 32; 3426 } 3427 if ( p == 0L){ 3428 return new FDBigInt( r, nWords ); 3429 } else { 3430 r[nWords] = (int)p; 3431 return new FDBigInt( r, nWords+1 ); 3432 } 3433 } 3434 3435 3439 public FDBigInt 3440 mult( FDBigInt other ){ 3441 int r[] = new int[ nWords + other.nWords ]; 3443 int i; 3444 3446 for( i = 0; i < this.nWords; i++ ){ 3447 long v = (long)this.data[i] & 0xffffffffL; long p = 0L; 3449 int j; 3450 for( j = 0; j < other.nWords; j++ ){ 3451 p += ((long)r[i+j]&0xffffffffL) + v*((long)other.data[j]&0xffffffffL); r[i+j] = (int)p; 3453 p >>>= 32; 3454 } 3455 r[i+j] = (int)p; 3456 } 3457 for ( i = r.length-1; i> 0; i--) 3459 if ( r[i] != 0 ) 3460 break; 3461 return new FDBigInt( r, i+1 ); 3462 } 3463 3464 3467 public FDBigInt 3468 add( FDBigInt other ){ 3469 int i; 3470 int a[], b[]; 3471 int n, m; 3472 long c = 0L; 3473 if ( this.nWords >= other.nWords ){ 3476 a = this.data; 3477 n = this.nWords; 3478 b = other.data; 3479 m = other.nWords; 3480 } else { 3481 a = other.data; 3482 n = other.nWords; 3483 b = this.data; 3484 m = this.nWords; 3485 } 3486 int r[] = new int[ n ]; 3487 for ( i = 0; i < n; i++ ){ 3488 c += (long)a[i] & 0xffffffffL; 3489 if ( i < m ){ 3490 c += (long)b[i] & 0xffffffffL; 3491 } 3492 r[i] = (int) c; 3493 c >>= 32; } 3495 if ( c != 0L ){ 3496 int s[] = new int[ r.length+1 ]; 3498 System.arraycopy( r, 0, s, 0, r.length ); 3499 s[i++] = (int)c; 3500 return new FDBigInt( s, i ); 3501 } 3502 return new FDBigInt( r, i ); 3503 } 3504 3505 3509 public FDBigInt 3510 sub( FDBigInt other ){ 3511 int r[] = new int[ this.nWords ]; 3512 int i; 3513 int n = this.nWords; 3514 int m = other.nWords; 3515 int nzeros = 0; 3516 long c = 0L; 3517 for ( i = 0; i < n; i++ ){ 3518 c += (long)this.data[i] & 0xffffffffL; 3519 if ( i < m ){ 3520 c -= (long)other.data[i] & 0xffffffffL; 3521 } 3522 if ( ( r[i] = (int) c ) == 0 ) 3523 nzeros++; 3524 else 3525 nzeros = 0; 3526 c >>= 32; } 3528 if ( c != 0L ) 3529 throw new RuntimeException ("Assertion botch: borrow out of subtract"); 3530 while ( i < m ) 3531 if ( other.data[i++] != 0 ) 3532 throw new RuntimeException ("Assertion botch: negative result of subtract"); 3533 return new FDBigInt( r, n-nzeros ); 3534 } 3535 3536 3542 public int 3543 cmp( FDBigInt other ){ 3544 int i; 3545 if ( this.nWords > other.nWords ){ 3546 int j = other.nWords-1; 3549 for ( i = this.nWords-1; i > j ; i-- ) 3550 if ( this.data[i] != 0 ) return 1; 3551 }else if ( this.nWords < other.nWords ){ 3552 int j = this.nWords-1; 3555 for ( i = other.nWords-1; i > j ; i-- ) 3556 if ( other.data[i] != 0 ) return -1; 3557 } else{ 3558 i = this.nWords-1; 3559 } 3560 for ( ; i > 0 ; i-- ) 3561 if ( this.data[i] != other.data[i] ) 3562 break; 3563 int a = this.data[i]; 3566 int b = other.data[i]; 3567 if ( a < 0 ){ 3568 if ( b < 0 ){ 3570 return a-b; } else { 3572 return 1; } 3574 } else { 3575 if ( b < 0 ) { 3577 return -1; 3579 } else { 3580 return a - b; 3581 } 3582 } 3583 } 3584 3585 3596 public int 3597 quoRemIteration( FDBigInt S )throws IllegalArgumentException { 3598 if ( nWords != S.nWords ){ 3602 throw new IllegalArgumentException ("disparate values"); 3603 } 3604 int n = nWords-1; 3608 long q = ((long)data[n]&0xffffffffL) / (long)S.data[n]; 3609 long diff = 0L; 3610 for ( int i = 0; i <= n ; i++ ){ 3611 diff += ((long)data[i]&0xffffffffL) - q*((long)S.data[i]&0xffffffffL); 3612 data[i] = (int)diff; 3613 diff >>= 32; } 3615 if ( diff != 0L ) { 3616 long sum = 0L; 3620 while ( sum == 0L ){ 3621 sum = 0L; 3622 for ( int i = 0; i <= n; i++ ){ 3623 sum += ((long)data[i]&0xffffffffL) + ((long)S.data[i]&0xffffffffL); 3624 data[i] = (int) sum; 3625 sum >>= 32; } 3627 3636 if ( sum !=0 && sum != 1 ) 3637 throw new RuntimeException ("Assertion botch: "+sum+" carry out of division correction"); 3638 q -= 1; 3639 } 3640 } 3641 long p = 0L; 3645 for ( int i = 0; i <= n; i++ ){ 3646 p += 10*((long)data[i]&0xffffffffL); 3647 data[i] = (int)p; 3648 p >>= 32; } 3650 if ( p != 0L ) 3651 throw new RuntimeException ("Assertion botch: carry out of *10"); 3652 3653 return (int)q; 3654 } 3655 3656 public long 3657 longValue(){ 3658 int i; 3661 for ( i = this.nWords-1; i > 1 ; i-- ){ 3662 if ( data[i] != 0 ){ 3663 throw new RuntimeException ("Assertion botch: value too big"); 3664 } 3665 } 3666 switch(i){ 3667 case 1: 3668 if ( data[1] < 0 ) 3669 throw new RuntimeException ("Assertion botch: value too big"); 3670 return ((long)(data[1]) << 32) | ((long)data[0]&0xffffffffL); 3671 case 0: 3672 return ((long)data[0]&0xffffffffL); 3673 default: 3674 throw new RuntimeException ("Assertion botch: longValue confused"); 3675 } 3676 } 3677 3678 public String 3679 toString() { 3680 StringBuilder r = new StringBuilder (30); 3681 r.append('['); 3682 int i = Math.min( nWords-1, data.length-1) ; 3683 if ( nWords > data.length ){ 3684 r.append( "("+data.length+"<"+nWords+"!)" ); 3685 } 3686 for( ; i> 0 ; i-- ){ 3687 r.append( Integer.toHexString( data[i] ) ); 3688 r.append( ' ' ); 3689 } 3690 r.append( Integer.toHexString( data[0] ) ); 3691 r.append( ']' ); 3692 return new String ( r ); 3693 } 3694} 3695} 3696 3697 | Popular Tags |