2 * @brief functions to serialise and unserialise a double
4 /* Copyright (C) 2006,2007,2008,2009,2015 Olly Betts
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 #include <xapian/error.h>
31 #include "serialise-double.h"
33 #include "wordaccess.h"
46 string
serialise_double(double v
)
48 # ifdef WORDS_BIGENDIAN
50 static_assert(sizeof(temp
) == sizeof(v
),
51 "Check if size of double and 64 bit int is same");
52 memcpy(&temp
, &v
, sizeof(double));
53 temp
= do_bswap(temp
);
54 return string(reinterpret_cast<const char *>(&temp
), sizeof(double));
56 return string(reinterpret_cast<const char *>(&v
), sizeof(double));
60 double unserialise_double(const char ** p
, const char * end
)
63 throw Xapian::SerialisationError(
64 "Bad encoded double: insufficient data");
67 # ifdef WORDS_BIGENDIAN
69 static_assert(sizeof(temp
) == sizeof(double),
70 "Check if size of double and 64 bit int is same");
71 memcpy(&temp
, *p
, sizeof(double));
72 temp
= do_bswap(temp
);
73 memcpy(&result
, &temp
, sizeof(double));
75 memcpy(&result
, *p
, sizeof(double));
83 string
serialise_double(double v
)
85 /* First bit(msb) -> sign (1 means negative)
86 * next 11 bits -> exponent
87 * last 52 bits -> mantissa
89 * frexp gives fraction within the range [0.5, 1)
90 * We multiply it by 2 to change the range to [1.0, 2.0)
91 * and reduce exp by 1, since this is the way doubles
92 * are stored in IEEE-754.
94 * Conversion of mantissa to bits is done by
95 * multiplying the mantissa with 2^52, converting
96 * it to a 64 bit integer representation of the original
100 static_assert(uint64_t(1) << 52 < numeric_limits
<double>::max(),
101 "Check if 2^52 can be represented by a double");
107 return string(reinterpret_cast<const char *>(&result
),
111 bool negative
= (v
< 0.0);
114 result
|= uint64_t(1) << 63;
123 result
|= uint64_t(exp
) << 52;
126 double scaled_v
= scalbn(v
, 52);
128 double scaled_v
= ldexp(v
, 52);
131 uint64_t scaled_v_int
= static_cast<uint64_t>(scaled_v
);
132 result
|= scaled_v_int
;
134 # ifdef WORDS_BIGENDIAN
135 result
= do_bswap(result
);
138 return string(reinterpret_cast<const char *>(&result
), sizeof(uint64_t));
141 double unserialise_double(const char ** p
, const char * end
) {
143 throw Xapian::SerialisationError(
144 "Bad encoded double: insufficient data");
146 unsigned char first
= *(*p
+ 7); // little-endian stored
147 unsigned char second
= *(*p
+ 6);
149 bool negative
= (first
& (0x80)) != 0;
151 // bitwise operations to extract exponent
152 int exp
= (first
& (0x80 - 1));
154 exp
|= (second
& (15 << 4)) >> 4;
157 uint64_t mantissa_bp
; // variable to store bit pattern of mantissa;
158 memcpy(&mantissa_bp
, *p
, sizeof(double));
159 mantissa_bp
&= (uint64_t(1) << 52) - 1;
163 if (exp
+ 1023 == 0 && mantissa_bp
== 0) return 0.0;
166 double result
= scalbn(mantissa_bp
, -52);
167 result
= scalbn(result
+ 1.0, exp
);
169 double result
= ldexp(mantissa_bp
, -52);
170 result
= ldexp(result
+ 1.0, exp
);
173 if (negative
) result
= -result
;