Ignore:
Timestamp:
07/08/20 01:53:39 (4 years ago)
Author:
Maciej Komosinski
Message:

Improved float-rounding functions, follow-up to r970

File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpp/common/nonstd_math.cpp

    r970 r979  
    44
    55#include "nonstd_math.h"
    6 #ifdef USE_PRINTFLOAT_DRAGON4
    76#include <PrintFloat/PrintFloat.h>
    8 #else
    97#include <sstream>
    10 #endif
     8#include <algorithm>    // std::min
    119
    1210RandomGenerator &rndGetInstance()
     
    1614}
    1715
     16std::string doubleToString(double x, int precision)
     17{
     18        std::stringstream ss;
     19        ss << std::fixed;
     20        ss.precision(precision); //set the number of places after decimal
     21        ss << x;
     22        return ss.str();
     23}
     24
    1825int doubleToString(double x, int precision, char *buffer, int bufferlen)
    1926{
     27        // C++ in 2020 and the impossible challenge https://stackoverflow.com/questions/277772/avoid-trailing-zeroes-in-printf
     28        if (precision < 0)
     29        {
     30                // The "g" format does not allow to use the number of decimal places after the decimal point. Dragon4 on the other hand fills in unnecessary trailinig zeros... so both are good only for "full precision".
    2031#ifdef USE_PRINTFLOAT_DRAGON4
    21         return PrintFloat64(buffer, bufferlen, x,
    22                 ((x < -1e17) || (x > 1e17) || ((x < 1e-4) && (x > -1e-4) && (x != 0.0)))
    23                 ? PrintFloatFormat_Scientific : PrintFloatFormat_Positional,
    24                 precision); //http://www.ryanjuckett.com/programming/printing-floating-point-numbers/
     32                return PrintFloat64(buffer, bufferlen, x,
     33                        ((x < -1e17) || (x > 1e17) || ((x < 1e-4) && (x > -1e-4) && (x != 0.0)))
     34                        ? PrintFloatFormat_Scientific : PrintFloatFormat_Positional,
     35                        precision); //http://www.ryanjuckett.com/programming/printing-floating-point-numbers/
    2536#else
    26         char format[10];
    27         sprintf(format, "%%.%dg", precision < 0 ? 17 : precision); //https://stackoverflow.com/questions/16839658/printf-width-specifier-to-maintain-precision-of-floating-point-value
    28         return sprintf(buffer, format, x);
     37                return sprintf(buffer, "%.17g", x);
    2938#endif
     39        }
     40        else
     41        {
     42                std::string s = doubleToString(x, precision);
     43                strncpy(buffer, s.c_str(), std::min(bufferlen, (int)s.length() + 1));
     44                buffer[bufferlen - 1] = 0; //ensure the string is truncated
     45                return s.length();
     46        }
    3047}
    3148
     
    3350double round(const double x, const int precision)
    3451{
    35 #ifdef USE_PRINTFLOAT_DRAGON4
    36         char buffer[30];
    37         doubleToString(x, precision, buffer, 30);
    38         double rounded = strtod(buffer, NULL);
    39 #else
    40         std::stringstream ss;
    41         ss << std::fixed;
    42         ss.precision(precision); // set the number of places after decimal
    43         ss << x;
    44         double rounded = stod(ss.str());
    45 #endif
     52        double rounded = std::stod(doubleToString(x, precision));
    4653        //printf("%d  %20g \t %20g\n", precision, x, rounded); //for debugging
    4754        return rounded;
Note: See TracChangeset for help on using the changeset viewer.