Menu

Loss of float-type info

2008-01-23
2013-04-22
  • Christopher Dunn

    When a value is 42.0, it is printed as '42', sans the decimal point.  Then it is read back as an integer!

    The problem is here:

    std::string valueToString( double value )
    {
       char buffer[32];
       sprintf(buffer, "%.16g", value);
       return buffer;
    }

    According to my ISO C book, we need
      "%#.16g"
    since the # will cause the decimal point to be retained always.

    Unfortunately, this will print
      42.00000000000000
    (14 zeroes)

    That is better than an integer, but it will increase the size of the output JSON file.  Ideally the code could be altered to scan the buffer before returning.  If it is a decimal followed by all zeroes, it should be truncated to just the decimal.
      42.
    That's easy code to write, but I am having trouble with Subversion right now.  I've made this change in my local copy.

    std::string valueToString( double value )
    {
       char buffer[32];
    #ifdef __STDC_SECURE_LIB__ // Use secure version with visual studio 2005 to avoid warning.
       sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
    #else   
       sprintf(buffer, "%#.16g", value);
    #endif
       char* last = buffer + 30;
       while(last > buffer && *last == '0') --last;
       if (*last == '.') *(last+1) = '\0';
       return buffer;
    }

    The tests still pass.  (By the way, StyledStreamWriter uses tabs instead of spaces so that the output file-size is dominated by actual data.)

     
    • Christopher Dunn

      This is better (and fixes a bug).  It truncates zeroes even if not all digits after the decimal are zero, and it keeps the last zero for clarity.

      std::string valueToString( double value )
      {
        std::cerr << "double:" << value << "\n";
         char buffer[32];
      #ifdef __STDC_SECURE_LIB__ // Use secure version with visual studio 2005 to avoid warning.
         sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
      #else   
         sprintf(buffer, "%#.16g", value);
      #endif
         char* ch = buffer + strlen(buffer) - 1;
         if (*ch != '0') return buffer; // nothing to truncate, so save time
         while(ch > buffer && *ch == '0'){
           --ch;
         }
         char* last_nonzero = ch;
         while(ch >= buffer){
           switch(*ch){
           case '0':
           case '1':
           case '2':
           case '3':
           case '4':
           case '5':
           case '6':
           case '7':
           case '8':
           case '9':
             --ch;
             continue;
           case '.':
             // Truncate zeroes to save bytes in output, but keep one.
             *(last_nonzero+2) = '\0';
             std::cerr << "current:" << buffer << std::endl;
             return buffer;
           default:
             return buffer;
           }
         }
         return buffer;
      }

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.