001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2012-2012 Pentaho 008// All Rights Reserved. 009 */ 010package mondrian.util; 011 012/** 013 * Representation of a number as a list of digits. 014 * 015 * @author tkafalas 016 */ 017class MondrianFloatingDecimal { 018 boolean isExceptional; 019 boolean isNegative; 020 int decExponent; 021 char digits[]; 022 int nDigits; 023 private final DigitList digitList = new DigitList(); 024 private final DigitList expDigitList = new DigitList(); 025 026 private static final int MAX_SIGNIFICANT_DIGITS = 19; 027 028 public MondrianFloatingDecimal(double d) { 029 if (d < 0) { 030 isNegative = true; 031 d = -d; 032 } else { 033 isNegative = false; 034 } 035 digitList.set(d, MAX_SIGNIFICANT_DIGITS, true); 036 nDigits = 0; 037 for (int i = 0; i < digitList.digits.length; i++) { 038 if (digitList.digits[i] != 0) { 039 nDigits++; 040 } 041 } 042 digits = toCharArray(digitList.digits); 043 isExceptional = Double.isInfinite(d); 044 decExponent = digitList.decimalAt; 045 } 046 047 public String toString() { 048 final StringBuilder s = new StringBuilder(MAX_SIGNIFICANT_DIGITS); 049 if (nDigits == 0) { 050 return "0"; 051 } 052 if (isNegative) { 053 s.append("-"); 054 } 055 if (decExponent < -5) { 056 s.append('.').append(digits).append("E-").append(decExponent); 057 } else { 058 if (decExponent < 0) { 059 s.append('.'); 060 for (int i = 0; i < decExponent; i++) { 061 s.append('0'); 062 } 063 s.append(digits); 064 } else { 065 if (decExponent < nDigits) { 066 s.append(digits, 0, decExponent).append(".") 067 .append(digits, decExponent, nDigits - decExponent); 068 } else { 069 if (decExponent == nDigits) { 070 s.append(digits); 071 } else { 072 if (decExponent < nDigits + 10) { 073 s.append(digits); 074 for (int i = 0; i < decExponent - nDigits; i++) { 075 s.append('0'); 076 } 077 } else { 078 s.append('.').append(digits).append("E") 079 .append(decExponent); 080 } 081 } 082 } 083 } 084 } 085 return s.toString(); 086 } 087 088 /** 089 * Appends {@link #decExponent} to result string. Returns i plus the 090 * number of chars written. 091 * 092 * <p>Implementation may assume that exponent has 3 or fewer digits.</p> 093 * 094 * <p>For example, given {@code decExponent} = 2, 095 * {@code formatExponent(result, 5, true, 2)} 096 * will write '0' into result[5] 097 * and '2' into result[6] and return 7.</p> 098 * 099 * @param result Result buffer 100 * @param i Initial offset into result buffer 101 * @param expSign Whether to print a '+' sign if exponent is positive 102 * (always prints '-' if negative) 103 * @param minExpDigits Minimum number of digits to write 104 * @return Offset into result buffer after writing chars 105 */ 106 public int formatExponent( 107 char[] result, 108 int i, 109 boolean expSign, 110 int minExpDigits) 111 { 112 int useExp = nDigits == 0 ? 0 : decExponent - 1; 113 expDigitList.set(Math.abs(useExp)); 114 if (useExp < 0 || expSign) { 115 result[i++] = useExp < 0 ? '-' : '+'; 116 } 117 if (minExpDigits > expDigitList.decimalAt) { 118 for (int j = 0; j < minExpDigits - expDigitList.decimalAt; j++) { 119 result[i++] = '0'; 120 } 121 } 122 for (int j = 0; j < expDigitList.decimalAt; j++) { 123 result[i++] = ((char) expDigitList.digits[j]); 124 } 125 return i; 126 } 127 128 private char[] toCharArray(byte[] bytes) { 129 char[] chars = new char[bytes.length]; 130 for (int i = 0; i < bytes.length; i++) { 131 chars[i] = (char) bytes[i]; 132 } 133 return chars; 134 } 135} 136 137// End MondrianFloatingDecimal.java