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