OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (C) 2015, International Business Machines |
| 3 * Corporation and others. All Rights Reserved. |
| 4 * |
| 5 * file name: visibledigits.cpp |
| 6 */ |
| 7 |
| 8 #include <math.h> |
| 9 |
| 10 #include "unicode/utypes.h" |
| 11 |
| 12 #if !UCONFIG_NO_FORMATTING |
| 13 |
| 14 #include "cstring.h" |
| 15 #include "decNumber.h" |
| 16 #include "digitlst.h" |
| 17 #include "uassert.h" |
| 18 #include "visibledigits.h" |
| 19 |
| 20 static const int32_t kNegative = 1; |
| 21 static const int32_t kInfinite = 2; |
| 22 static const int32_t kNaN = 4; |
| 23 |
| 24 U_NAMESPACE_BEGIN |
| 25 |
| 26 void VisibleDigits::setNegative() { |
| 27 fFlags |= kNegative; |
| 28 } |
| 29 |
| 30 void VisibleDigits::setNaN() { |
| 31 fFlags |= kNaN; |
| 32 } |
| 33 |
| 34 void VisibleDigits::setInfinite() { |
| 35 fFlags |= kInfinite; |
| 36 } |
| 37 |
| 38 void VisibleDigits::clear() { |
| 39 fInterval.clear(); |
| 40 fDigits.clear(); |
| 41 fExponent = 0; |
| 42 fFlags = 0; |
| 43 fAbsIntValue = 0LL; |
| 44 fAbsIntValueSet = FALSE; |
| 45 fAbsDoubleValue = 0.0; |
| 46 fAbsDoubleValueSet = FALSE; |
| 47 } |
| 48 |
| 49 UBool VisibleDigits::isNegative() const { |
| 50 return (fFlags & kNegative); |
| 51 } |
| 52 |
| 53 UBool VisibleDigits::isNaN() const { |
| 54 return (fFlags & kNaN); |
| 55 } |
| 56 |
| 57 UBool VisibleDigits::isInfinite() const { |
| 58 return (fFlags & kInfinite); |
| 59 } |
| 60 |
| 61 int32_t VisibleDigits::getDigitByExponent(int32_t digitPos) const { |
| 62 if (digitPos < fExponent || digitPos >= fExponent + fDigits.length()) { |
| 63 return 0; |
| 64 } |
| 65 const char *ptr = fDigits.data(); |
| 66 return ptr[digitPos - fExponent]; |
| 67 } |
| 68 |
| 69 UBool VisibleDigits::isOverMaxDigits() const { |
| 70 return (fExponent + fDigits.length() > fInterval.getMostSignificantExclusive
()); |
| 71 } |
| 72 |
| 73 UBool VisibleDigits::isNaNOrInfinity() const { |
| 74 return (fFlags & (kInfinite | kNaN)) != 0; |
| 75 } |
| 76 |
| 77 double VisibleDigits::computeAbsDoubleValue() const { |
| 78 // Take care of NaN and infinity |
| 79 if (isNaN()) { |
| 80 return uprv_getNaN(); |
| 81 } |
| 82 if (isInfinite()) { |
| 83 return uprv_getInfinity(); |
| 84 } |
| 85 |
| 86 // stack allocate a decNumber to hold MAX_DBL_DIGITS+3 significant digits |
| 87 char rawNumber[sizeof(decNumber) + MAX_DBL_DIGITS+3]; |
| 88 decNumber *numberPtr = (decNumber *) rawNumber; |
| 89 |
| 90 int32_t mostSig = fInterval.getMostSignificantExclusive(); |
| 91 int32_t mostSigNonZero = fExponent + fDigits.length(); |
| 92 int32_t end = mostSig > mostSigNonZero ? mostSigNonZero : mostSig; |
| 93 int32_t leastSig = fInterval.getLeastSignificantInclusive(); |
| 94 int32_t start = leastSig > fExponent ? leastSig : fExponent; |
| 95 if (end <= start) { |
| 96 return 0.0; |
| 97 } |
| 98 if (start < end - (MAX_DBL_DIGITS+3)) { |
| 99 start = end - (MAX_DBL_DIGITS+3); |
| 100 } |
| 101 uint8_t *pos = numberPtr->lsu; |
| 102 const char *src = &(fDigits.data()[start - fExponent]); |
| 103 for (int32_t i = start; i < end; ++i) { |
| 104 *pos++ = (uint8_t) (*src++); |
| 105 } |
| 106 numberPtr->exponent = start; |
| 107 numberPtr->bits = 0; |
| 108 numberPtr->digits = end - start; |
| 109 char str[MAX_DBL_DIGITS+18]; |
| 110 uprv_decNumberToString(numberPtr, str); |
| 111 U_ASSERT(uprv_strlen(str) < MAX_DBL_DIGITS+18); |
| 112 char decimalSeparator = DigitList::getStrtodDecimalSeparator(); |
| 113 if (decimalSeparator != '.') { |
| 114 char *decimalPt = strchr(str, '.'); |
| 115 if (decimalPt != NULL) { |
| 116 *decimalPt = decimalSeparator; |
| 117 } |
| 118 } |
| 119 char *unused = NULL; |
| 120 return uprv_strtod(str, &unused); |
| 121 } |
| 122 |
| 123 void VisibleDigits::getFixedDecimal( |
| 124 double &source, int64_t &intValue, int64_t &f, int64_t &t, int32_t &v, UBool
&hasIntValue) const { |
| 125 source = 0.0; |
| 126 intValue = 0; |
| 127 f = 0; |
| 128 t = 0; |
| 129 v = 0; |
| 130 hasIntValue = FALSE; |
| 131 if (isNaNOrInfinity()) { |
| 132 return; |
| 133 } |
| 134 |
| 135 // source |
| 136 if (fAbsDoubleValueSet) { |
| 137 source = fAbsDoubleValue; |
| 138 } else { |
| 139 source = computeAbsDoubleValue(); |
| 140 } |
| 141 |
| 142 // visible decimal digits |
| 143 v = fInterval.getFracDigitCount(); |
| 144 |
| 145 // intValue |
| 146 |
| 147 // If we initialized from an int64 just use that instead of |
| 148 // calculating |
| 149 if (fAbsIntValueSet) { |
| 150 intValue = fAbsIntValue; |
| 151 } else { |
| 152 int32_t startPos = fInterval.getMostSignificantExclusive(); |
| 153 if (startPos > 18) { |
| 154 startPos = 18; |
| 155 } |
| 156 // process the integer digits |
| 157 for (int32_t i = startPos - 1; i >= 0; --i) { |
| 158 intValue = intValue * 10LL + getDigitByExponent(i); |
| 159 } |
| 160 if (intValue == 0LL && startPos > 0) { |
| 161 intValue = 100000000000000000LL; |
| 162 } |
| 163 } |
| 164 |
| 165 // f (decimal digits) |
| 166 // skip over any leading 0's in fraction digits. |
| 167 int32_t idx = -1; |
| 168 for (; idx >= -v && getDigitByExponent(idx) == 0; --idx); |
| 169 |
| 170 // Only process up to first 18 non zero fraction digits for decimalDigits |
| 171 // since that is all we can fit into an int64. |
| 172 for (int32_t i = idx; i >= -v && i > idx - 18; --i) { |
| 173 f = f * 10LL + getDigitByExponent(i); |
| 174 } |
| 175 |
| 176 // If we have no decimal digits, we don't have an integer value |
| 177 hasIntValue = (f == 0LL); |
| 178 |
| 179 // t (decimal digits without trailing zeros) |
| 180 t = f; |
| 181 while (t > 0 && t % 10LL == 0) { |
| 182 t /= 10; |
| 183 } |
| 184 } |
| 185 |
| 186 U_NAMESPACE_END |
| 187 #endif /* #if !UCONFIG_NO_FORMATTING */ |
OLD | NEW |