c++ - how to save a double matrix quickly and compactly if some loss of precision is acceptable? -


i have matrix of double size 1024x1024. want write file. here solution this. accepted answer 50-60% more time efficient second answer in question expected (according simple test write file in both methods).

there solution write csv file(accepted answer in question), slower(3-4 times slower)

while i'm writing file number of floating point of each element in matrix 16 , output following:

-1.6819883882999420e-001 -3.5269531607627869e-001 2.4137189984321594e-001 -3.9325976371765137e-001 -2.2069962322711945e-001 -5.9525445103645325e-002

when write file, file size becomes 24 mb in first way(first link, accepted answer) , 37 mb in third way(second link, accepted answer) both of unacceptable.

i need set precision of matrix in fast way , output become -1.6819e-01 -3.5269e-01. appreciated.

what i'm doing read image of 1024x1024, process it, write output mat(which double) file. consider have, thousands of image, images less 1 mb, running time each image less 1 sec without saving.

edit: when save same matrix in matlab, becomes 6.75 mb

edit

  • now has option store in 16bit floats.
    • you lose precision(depends on data range,vary rnd distribution see different error rates).
    • slower(20-30ms)(see link below faster tricks if matters)
    • 2mb
  • if know nature of data(range,distribution surface(maybe variable length encoding)) more can done

code

//using code lifted http://www.mathworks.com/matlabcentral/fileexchange/23173     #include "opencv2/opencv.hpp" #include <string.h> #include <math.h>  using namespace cv;  #define  int16_type          short #define uint16_type unsigned short #define  int32_type          long #define uint32_type unsigned long  int doubles2halfp(void *target, void *source, int numel); int halfp2doubles(void *target, void *source, int numel);  void writemat(char* fpath,mat& data,bool isf16) {      file* fp = fopen(fpath,"wb");     if (!fp)perror("fopen");     double dbuf[1024];      for(int i=0;i<1024;++i)     {         for(int j=0;j<1024;++j)             dbuf[j]=data.at<double>(i,j);              if(isf16)         {             uint16_type hbuf[1024];             doubles2halfp(&hbuf,&dbuf,1024);             fwrite(&hbuf,sizeof(uint16_type),1024,fp);         }else         {             fwrite(&dbuf,sizeof(double),1024,fp);         }     }     fclose(fp); }  void readmat(char* fpath,mat& data,bool isf16) {     file* fp = fopen(fpath,"rb");     if (!fp)perror("fopen");      double dbuf[1024];     for(int i=0;i<1024;++i)     {         if(isf16)         {             uint16_type hbuf[1024];             fread(&hbuf,sizeof(uint16_type),1024,fp);             halfp2doubles(&dbuf,&hbuf,1024);         }else{              fread(&dbuf,sizeof(double),1024,fp);         }         for(int j=0;j<1024;++j)         {             data.at<double>(i,j)=dbuf[j];         }     }     fclose(fp); }  int main() {     rng rng=  therng();     mat data = mat::zeros(size(1024,1024),cv_64fc1);     for(int i=0;i<1024;++i)         for(int j=0;j<1024;++j)             data.at<double>(i,j)=rng.uniform(-1.,1.);      writemat("img.bin",data,true);       mat res = mat::zeros(size(1024,1024),cv_64fc1);     readmat("img.bin",res,true);      double error=0;     for(int i=0;i<1024;++i)         for(int j=0;j<1024;++j)         {             //printf("%f %f\n",data.at<double>(i,j),res.at<double>(i,j));             error+=abs(data.at<double>(i,j)-res.at<double>(i,j));         }     printf("err=%f avgerr=%f\n",error,error/1024/1024);      getchar();     return 0; }  //////////////////////////////////////// //////////////////////////////////////// //////////////////////////////////////// ////////////////////////////////////////   int doubles2halfp(void *target, void *source, int numel) {     uint16_type *hp = (uint16_type *) target; // type pun output unsigned 16-bit int     uint32_type *xp = (uint32_type *) source; // type pun input unsigned 32-bit int     uint16_type    hs, he, hm;     uint32_type x, xs, xe, xm;     int hes;     static int next;  // little endian adjustment     static int checkieee = 1;  // flag check ieee754, endian, , word size     double 1 = 1.0; // used checking ieee754 floating point format     uint32_type *ip; // used checking ieee754 floating point format      if( checkieee ) { // 1st call, check ieee754, endian, , word size         ip = (uint32_type *) &one;         if( *ip ) { // if big endian, no adjustment             next = 0;         } else { // if little endian, adjustment necessary             next = 1;             ip++;         }         if( *ip != 0x3ff00000u ) { // check exact ieee 754 bit pattern of 1.0             return 1;  // floating point bit pattern not ieee 754         }         if( sizeof(int16_type) != 2 || sizeof(int32_type) != 4 ) {             return 1;  // short not 16-bits, or long not 32-bits.         }         checkieee = 0; // checks out ok     }      xp += next;  // little endian adjustment if necessary      if( source == null || target == null ) { // nothing convert (e.g., imag part of pure real)         return 0;     }      while( numel-- ) {         x = *xp++; xp++; // xp++ skip on remaining 32 bits of mantissa         if( (x & 0x7fffffffu) == 0 ) {  // signed 0             *hp++ = (uint16_type) (x >> 16);  // return signed 0         } else { // not 0             xs = x & 0x80000000u;  // pick off sign bit             xe = x & 0x7ff00000u;  // pick off exponent bits             xm = x & 0x000fffffu;  // pick off mantissa bits             if( xe == 0 ) {  // denormal underflow, return signed 0                 *hp++ = (uint16_type) (xs >> 16);             } else if( xe == 0x7ff00000u ) {  // inf or nan (all exponent bits set)                 if( xm == 0 ) { // if mantissa 0 ...                     *hp++ = (uint16_type) ((xs >> 16) | 0x7c00u); // signed inf                 } else {                     *hp++ = (uint16_type) 0xfe00u; // nan, 1st mantissa bit set                 }             } else { // normalized number                 hs = (uint16_type) (xs >> 16); // sign bit                 hes = ((int)(xe >> 20)) - 1023 + 15; // exponent unbias double, bias halfp                 if( hes >= 0x1f ) {  // overflow                     *hp++ = (uint16_type) ((xs >> 16) | 0x7c00u); // signed inf                 } else if( hes <= 0 ) {  // underflow                     if( (10 - hes) > 21 ) {  // mantissa shifted way off & no rounding possibility                         hm = (uint16_type) 0u;  // set mantissa 0                     } else {                         xm |= 0x00100000u;  // add hidden leading bit                         hm = (uint16_type) (xm >> (11 - hes)); // mantissa                         if( (xm >> (10 - hes)) & 0x00000001u ) // check rounding                             hm += (uint16_type) 1u; // round, might overflow exp bit, ok                     }                     *hp++ = (hs | hm); // combine sign bit , mantissa bits, biased exponent 0                 } else {                     = (uint16_type) (hes << 10); // exponent                     hm = (uint16_type) (xm >> 10); // mantissa                     if( xm & 0x00000200u ) // check rounding                         *hp++ = (hs | | hm) + (uint16_type) 1u; // round, might overflow inf, ok                     else                         *hp++ = (hs | | hm);  // no rounding                 }             }         }     }     return 0; }  int halfp2doubles(void *target, void *source, int numel) {     uint16_type *hp = (uint16_type *) source; // type pun input unsigned 16-bit int     uint32_type *xp = (uint32_type *) target; // type pun output unsigned 32-bit int     uint16_type h, hs, he, hm;     uint32_type xs, xe, xm;     int32_type xes;     int e;     static int next;  // little endian adjustment     static int checkieee = 1;  // flag check ieee754, endian, , word size     double 1 = 1.0; // used checking ieee754 floating point format     uint32_type *ip; // used checking ieee754 floating point format      if( checkieee ) { // 1st call, check ieee754, endian, , word size         ip = (uint32_type *) &one;         if( *ip ) { // if big endian, no adjustment             next = 0;         } else { // if little endian, adjustment necessary             next = 1;             ip++;         }         if( *ip != 0x3ff00000u ) { // check exact ieee 754 bit pattern of 1.0             return 1;  // floating point bit pattern not ieee 754         }         if( sizeof(int16_type) != 2 || sizeof(int32_type) != 4 ) {             return 1;  // short not 16-bits, or long not 32-bits.         }         checkieee = 0; // checks out ok     }      xp += next;  // little endian adjustment if necessary      if( source == null || target == null ) // nothing convert (e.g., imag part of pure real)         return 0;      while( numel-- ) {         h = *hp++;         if( (h & 0x7fffu) == 0 ) {  // signed 0             *xp++ = ((uint32_type) h) << 16;  // return signed 0         } else { // not 0             hs = h & 0x8000u;  // pick off sign bit             = h & 0x7c00u;  // pick off exponent bits             hm = h & 0x03ffu;  // pick off mantissa bits             if( == 0 ) {  // denormal convert normalized                 e = -1; // following loop figures out how adjust exponent                 {                     e++;                     hm <<= 1;                 } while( (hm & 0x0400u) == 0 ); // shift until leading bit overflows exponent bit                 xs = ((uint32_type) hs) << 16; // sign bit                 xes = ((int32_type) (he >> 10)) - 15 + 1023 - e; // exponent unbias halfp, bias double                 xe = (uint32_type) (xes << 20); // exponent                 xm = ((uint32_type) (hm & 0x03ffu)) << 10; // mantissa                 *xp++ = (xs | xe | xm); // combine sign bit, exponent bits, , mantissa bits             } else if( == 0x7c00u ) {  // inf or nan (all exponent bits set)                 if( hm == 0 ) { // if mantissa 0 ...                     *xp++ = (((uint32_type) hs) << 16) | ((uint32_type) 0x7ff00000u); // signed inf                 } else {                     *xp++ = (uint32_type) 0xfff80000u; // nan, 1st mantissa bit set                 }             } else {                 xs = ((uint32_type) hs) << 16; // sign bit                 xes = ((int32_type) (he >> 10)) - 15 + 1023; // exponent unbias halfp, bias double                 xe = (uint32_type) (xes << 20); // exponent                 xm = ((uint32_type) hm) << 10; // mantissa                 *xp++ = (xs | xe | xm); // combine sign bit, exponent bits, , mantissa bits             }         }         xp++; // skip on remaining 32 bits of mantissa     }     return 0; } 

Comments

Popular posts from this blog

java.util.scanner - How to read and add only numbers to array from a text file -

rewrite - Trouble with Wordpress multiple custom querystrings -