1
+ // Copyright 2025 Google LLC
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // https://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ #include " quadruple.h"
16
+ #include " quadruple_builder.h"
17
+ #include < ctype.h>
18
+ #include < stdint.h>
19
+ #include < cmath>
20
+ #include < limits>
21
+
22
+ namespace firebase {
23
+ namespace firestore {
24
+ namespace util {
25
+
26
+ namespace {
27
+ constexpr int64_t kHashCodeOfNan = 7652541255 ;
28
+ }
29
+
30
+ Quadruple::Quadruple (double x) {
31
+ negative_ = signbit (x);
32
+ switch (fpclassify (x)) {
33
+ case FP_NAN:
34
+ negative_ = false ;
35
+ exponent_ = kInfiniteExponent ;
36
+ mantissa_hi_ = 1ULL << 63 ;
37
+ mantissa_lo_ = 0 ;
38
+ break ;
39
+ case FP_INFINITE:
40
+ exponent_ = kInfiniteExponent ;
41
+ mantissa_hi_ = 0 ;
42
+ mantissa_lo_ = 0 ;
43
+ break ;
44
+ case FP_ZERO:
45
+ exponent_ = 0 ;
46
+ mantissa_hi_ = 0 ;
47
+ mantissa_lo_ = 0 ;
48
+ break ;
49
+ case FP_SUBNORMAL:
50
+ case FP_NORMAL:
51
+ negative_ = x < 0 ;
52
+ int x_exponent;
53
+ double small = frexp (std::abs (x), &x_exponent);
54
+ exponent_ = static_cast <uint32_t >(x_exponent - 1 ) + kExponentBias ;
55
+ // Scale 'small' to its 53-bit mantissa value as a long, then left-justify
56
+ // it with the leading 1 bit dropped in mantissa_hi (65-53=12).
57
+ mantissa_hi_ = static_cast <uint64_t >(ldexp (small, 53 )) << 12 ;
58
+ mantissa_lo_ = 0 ;
59
+ break ;
60
+ }
61
+ }
62
+ Quadruple::Quadruple (int64_t x) {
63
+ if (x == 0 ) {
64
+ negative_ = false ;
65
+ exponent_ = 0 ;
66
+ mantissa_hi_ = 0 ;
67
+ mantissa_lo_ = 0 ;
68
+ } else if (x == std::numeric_limits<int64_t >::min ()) {
69
+ // -2^63 cannot be negated, so special-case it.
70
+ negative_ = true ;
71
+ exponent_ = 63 + kExponentBias ;
72
+ mantissa_hi_ = 0 ;
73
+ mantissa_lo_ = 0 ;
74
+ } else {
75
+ negative_ = x < 0 ;
76
+ if (negative_) {
77
+ x = -x;
78
+ }
79
+ if (x == 1 ) {
80
+ // The shift below wraps around for x=1, so special-case it.
81
+ exponent_ = kExponentBias ;
82
+ mantissa_hi_ = 0 ;
83
+ mantissa_lo_ = 0 ;
84
+ } else {
85
+ uint64_t ux = static_cast <uint64_t >(x);
86
+ int leading_zeros = __builtin_clzll (ux);
87
+ // Left-justify with the leading 1 dropped.
88
+ mantissa_hi_ = ux << (leading_zeros + 1 );
89
+ mantissa_lo_ = 0 ;
90
+ exponent_ = static_cast <uint32_t >(63 - leading_zeros) + kExponentBias ;
91
+ }
92
+ }
93
+ }
94
+ bool Quadruple::Parse (std::string s) {
95
+ if (s == " NaN" ) {
96
+ negative_ = false ;
97
+ exponent_ = kInfiniteExponent ;
98
+ mantissa_hi_ = 1LL << 63 ;
99
+ mantissa_lo_ = 0 ;
100
+ return true ;
101
+ }
102
+ if (s == " -Infinity" ) {
103
+ negative_ = true ;
104
+ exponent_ = kInfiniteExponent ;
105
+ mantissa_hi_ = 0 ;
106
+ mantissa_lo_ = 0 ;
107
+ return true ;
108
+ }
109
+ if (s == " Infinity" || s == " +Infinity" ) {
110
+ negative_ = false ;
111
+ exponent_ = kInfiniteExponent ;
112
+ mantissa_hi_ = 0 ;
113
+ mantissa_lo_ = 0 ;
114
+ return true ;
115
+ }
116
+ bool negative = false ;
117
+ int len = s.size ();
118
+ uint8_t * digits = new uint8_t [len];
119
+ int i = 0 ;
120
+ int j = 0 ;
121
+ int64_t exponent = 0 ;
122
+ if (i < len) {
123
+ if (s[i] == ' -' ) {
124
+ negative = true ;
125
+ i++;
126
+ } else if (s[i] == ' +' ) {
127
+ i++;
128
+ }
129
+ }
130
+ // int firstDigit = i;
131
+ while (i < len && isdigit (s[i])) {
132
+ digits[j++] = static_cast <uint8_t >(s[i++] - ' 0' );
133
+ }
134
+ if (i < len && s[i] == ' .' ) {
135
+ int decimal = ++i;
136
+ while (i < len && isdigit (s[i])) {
137
+ digits[j++] = static_cast <uint8_t >(s[i++] - ' 0' );
138
+ }
139
+ exponent = decimal - i;
140
+ }
141
+ if (i < len && (s[i] == ' e' || s[i] == ' E' )) {
142
+ int64_t exponentValue = 0 ;
143
+ i++;
144
+ int exponentSign = 1 ;
145
+ if (i < len) {
146
+ if (s[i] == ' -' ) {
147
+ exponentSign = -1 ;
148
+ i++;
149
+ } else if (s[i] == ' +' ) {
150
+ i++;
151
+ }
152
+ }
153
+ int firstExponent = i;
154
+ while (i < len && isdigit (s[i])) {
155
+ exponentValue = exponentValue * 10 + s[i++] - ' 0' ;
156
+ if (i - firstExponent > 9 ) {
157
+ return false ;
158
+ }
159
+ }
160
+ if (i == firstExponent) {
161
+ return false ;
162
+ }
163
+ exponent += exponentValue * exponentSign;
164
+ }
165
+ if (j == 0 || i != len) {
166
+ return false ;
167
+ }
168
+ std::vector<uint8_t > digits_copy (j);
169
+ for (int k = 0 ; k < j; k++) {
170
+ digits_copy[k] = digits[k];
171
+ }
172
+ QuadrupleBuilder parsed;
173
+ parsed.parseDecimal (digits_copy, exponent);
174
+ negative_ = negative;
175
+ exponent_ = parsed.exponent ;
176
+ mantissa_hi_ = parsed.mantHi ;
177
+ mantissa_lo_ = parsed.mantLo ;
178
+ return true ;
179
+ }
180
+ // Compare two quadruples, with -0 < 0, and NaNs larger than all numbers.
181
+ int Quadruple::Compare (const Quadruple& other) const {
182
+ int lessThan;
183
+ int greaterThan;
184
+ if (negative_) {
185
+ if (!other.negative_ ) {
186
+ return -1 ;
187
+ }
188
+ lessThan = 1 ;
189
+ greaterThan = -1 ;
190
+ } else {
191
+ if (other.negative_ ) {
192
+ return 1 ;
193
+ }
194
+ lessThan = -1 ;
195
+ greaterThan = 1 ;
196
+ }
197
+ if (exponent_ < other.exponent_ ) {
198
+ return lessThan;
199
+ } else if (exponent_ > other.exponent_ ) {
200
+ return greaterThan;
201
+ } else if (mantissa_hi_ < other.mantissa_hi_ ) {
202
+ return lessThan;
203
+ } else if (mantissa_hi_ > other.mantissa_hi_ ) {
204
+ return greaterThan;
205
+ } else if (mantissa_lo_ < other.mantissa_lo_ ) {
206
+ return lessThan;
207
+ } else if (mantissa_lo_ > other.mantissa_lo_ ) {
208
+ return greaterThan;
209
+ } else {
210
+ return 0 ;
211
+ }
212
+ }
213
+ Quadruple::operator double () const {
214
+ switch (exponent_) {
215
+ case 0 :
216
+ // zero or Quadruple subnormal
217
+ return negative_ ? -0.0 : 0.0 ;
218
+ case kInfiniteExponent : {
219
+ if (is_nan ()) {
220
+ return NAN;
221
+ }
222
+ return negative_ ? -INFINITY : INFINITY;
223
+ }
224
+ default :
225
+ int32_t unbiased_exp = static_cast <int32_t >(exponent_ - kExponentBias );
226
+ return scalb ((1LL << 52 ) | (mantissa_hi_ >> 12 ), -52 + unbiased_exp) *
227
+ (negative_ ? -1 : 1 );
228
+ }
229
+ }
230
+ int64_t Quadruple::HashValue () const {
231
+ if (is_nan ()) {
232
+ return kHashCodeOfNan ;
233
+ }
234
+ const int64_t prime = 31 ;
235
+ int64_t result = 1 ;
236
+ result = prime * result + static_cast <uint64_t >(exponent_);
237
+ result = prime * result + static_cast <uint64_t >(mantissa_hi_);
238
+ result = prime * result + static_cast <uint64_t >(mantissa_lo_);
239
+ result = prime * result + (negative_ ? 1231 : 1237 );
240
+ return result;
241
+ }
242
+
243
+ } // namespace util
244
+ } // namespace firestore
245
+ } // namespace firebase
0 commit comments