LCOV - code coverage report
Current view: top level - common - serialise-double.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 2463e5ebed6d Lines: 7 8 87.5 %
Date: 2019-03-18 07:48:51 Functions: 2 2 100.0 %
Branches: 2 10 20.0 %

           Branch data     Line data    Source code
       1                 :            : /** @file serialise-double.cc
       2                 :            :  * @brief functions to serialise and unserialise a double
       3                 :            :  */
       4                 :            : /* Copyright (C) 2006,2007,2008,2009,2015 Olly Betts
       5                 :            :  *
       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:
      12                 :            :  *
      13                 :            :  * The above copyright notice and this permission notice shall be included in
      14                 :            :  * all copies or substantial portions of the Software.
      15                 :            :  *
      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
      22                 :            :  * IN THE SOFTWARE.
      23                 :            :  */
      24                 :            : 
      25                 :            : #include <config.h>
      26                 :            : 
      27                 :            : #include <xapian/error.h>
      28                 :            : 
      29                 :            : #include "omassert.h"
      30                 :            : 
      31                 :            : #include "serialise-double.h"
      32                 :            : 
      33                 :            : #include "wordaccess.h"
      34                 :            : 
      35                 :            : #include <cfloat>
      36                 :            : #include <cmath>
      37                 :            : 
      38                 :            : #include <algorithm>
      39                 :            : #include <string>
      40                 :            : 
      41                 :            : using namespace std;
      42                 :            : 
      43                 :            : #ifdef FOLLOWS_IEEE
      44                 :            : 
      45                 :     218176 : string serialise_double(double v)
      46                 :            : {
      47                 :            : # ifdef WORDS_BIGENDIAN
      48                 :            :     uint64_t temp;
      49                 :            :     static_assert(sizeof(temp) == sizeof(v),
      50                 :            :                   "Check if size of double and 64 bit int is same");
      51                 :            :     memcpy(&temp, &v, sizeof(double));
      52                 :            :     temp = do_bswap(temp);
      53                 :            :     return string(reinterpret_cast<const char *>(&temp), sizeof(double));
      54                 :            : # else
      55         [ +  - ]:     218176 :     return string(reinterpret_cast<const char *>(&v), sizeof(double));
      56                 :            : # endif
      57                 :            : }
      58                 :            : 
      59                 :     218002 : double unserialise_double(const char ** p, const char * end)
      60                 :            : {
      61         [ -  + ]:     218002 :     if (end - *p < 8) {
      62                 :            :         throw Xapian::SerialisationError(
      63 [ #  # ][ #  # ]:          0 :             "Bad encoded double: insufficient data");
                 [ #  # ]
      64                 :            :     }
      65                 :            :     double result;
      66                 :            : # ifdef WORDS_BIGENDIAN
      67                 :            :     uint64_t temp;
      68                 :            :     static_assert(sizeof(temp) == sizeof(double),
      69                 :            :                   "Check if size of double and 64 bit int is same");
      70                 :            :     memcpy(&temp, *p, sizeof(double));
      71                 :            :     temp = do_bswap(temp);
      72                 :            :     memcpy(&result, &temp, sizeof(double));
      73                 :            : # else
      74                 :     218002 :     memcpy(&result, *p, sizeof(double));
      75                 :            : # endif
      76                 :     218002 :     *p += 8;
      77                 :     218002 :     return result;
      78                 :            : }
      79                 :            : 
      80                 :            : #else
      81                 :            : 
      82                 :            : string serialise_double(double v){
      83                 :            :     /*
      84                 :            :      * First bit(msb) -> sign (1 means negative)
      85                 :            :      * next 11 bits -> exponent
      86                 :            :      * last 52 bits -> mantissa
      87                 :            :      *
      88                 :            :      * frexp gives fraction within the range [0.5, 1)
      89                 :            :      * We multiply it by 2 to change the range to [1.0, 2.0)
      90                 :            :      * and reduce exp by 1, since this is the way doubles
      91                 :            :      * are stored in IEEE-754.
      92                 :            :      *
      93                 :            :      * Conversion of mantissa to bits is done by
      94                 :            :      * multiplying the mantissa with 2^52, converting
      95                 :            :      * it to a 64 bit integer representation of the original
      96                 :            :      * double.
      97                 :            :      */
      98                 :            : 
      99                 :            :     static_assert(uint64_t(1) << 52 < numeric_limits<double>::max(),
     100                 :            :                   "Check if 2^52 can be represented by a double");
     101                 :            : 
     102                 :            :     uint64_t result = 0;
     103                 :            : 
     104                 :            :     if (v == 0.0) {
     105                 :            :         result = 0;
     106                 :            :         return string(reinterpret_cast<const char *>(&result),
     107                 :            :                       sizeof(uint64_t));
     108                 :            :     }
     109                 :            : 
     110                 :            :     bool negative = (v < 0.0);
     111                 :            :     if (negative) {
     112                 :            :         v = -v;
     113                 :            :         result |= uint64_t(1) << 63;
     114                 :            :     }
     115                 :            : 
     116                 :            :     int exp;
     117                 :            :     v = frexp(v, &exp);
     118                 :            :     v *= 2.0;
     119                 :            :     v -= 1.0;
     120                 :            :     exp += 1022;
     121                 :            : 
     122                 :            :     result |= uint64_t(exp) << 52;
     123                 :            : 
     124                 :            : # if FLT_RADIX == 2
     125                 :            :     double scaled_v = scalbn(v, 52);
     126                 :            : # else
     127                 :            :     double scaled_v = ldexp(v, 52);
     128                 :            : # endif
     129                 :            : 
     130                 :            :     uint64_t scaled_v_int = static_cast<uint64_t>(scaled_v);
     131                 :            :     result |= scaled_v_int;
     132                 :            : 
     133                 :            : # ifdef WORDS_BIGENDIAN
     134                 :            :     result = do_bswap(result);
     135                 :            : # endif
     136                 :            : 
     137                 :            :     return string(reinterpret_cast<const char *>(&result), sizeof(uint64_t));
     138                 :            : }
     139                 :            : 
     140                 :            : double unserialise_double(const char ** p, const char * end) {
     141                 :            :     if (end - *p < 8) {
     142                 :            :         throw Xapian::SerialisationError(
     143                 :            :             "Bad encoded double: insufficient data");
     144                 :            :     }
     145                 :            :     unsigned char first = *(*p + 7); // little-endian stored
     146                 :            :     unsigned char second = *(*p + 6);
     147                 :            : 
     148                 :            :     bool negative = (first & (0x80)) != 0;
     149                 :            : 
     150                 :            :     // bitwise operations to extract exponent
     151                 :            :     int exp = (first & (0x80 - 1));
     152                 :            :     exp <<= 4;
     153                 :            :     exp |= (second & (15 << 4)) >> 4;
     154                 :            :     exp -= 1023;
     155                 :            : 
     156                 :            :     uint64_t mantissa_bp; // variable to store bit pattern of mantissa;
     157                 :            :     memcpy(&mantissa_bp, *p, sizeof(double));
     158                 :            :     mantissa_bp &= (uint64_t(1) << 52) - 1;
     159                 :            : 
     160                 :            :     *p += 8;
     161                 :            : 
     162                 :            :     if (exp + 1023 == 0 && mantissa_bp == 0) return 0.0;
     163                 :            : 
     164                 :            : # if FLT_RADIX == 2
     165                 :            :     double result = scalbn(mantissa_bp, -52);
     166                 :            :     result = scalbn(result + 1.0, exp);
     167                 :            : # else
     168                 :            :     double result = ldexp(mantissa_bp, -52);
     169                 :            :     result = ldexp(result + 1.0, exp);
     170                 :            : # endif
     171                 :            : 
     172                 :            :     if (negative) result = -result;
     173                 :            :     return result;
     174                 :            : }
     175                 :            : 
     176                 :            : #endif

Generated by: LCOV version 1.11