Skip to content

Commit

Permalink
Fix error in float_to_string_decimal_point
Browse files Browse the repository at this point in the history
(using the good to_string_nozero instead)
  • Loading branch information
remi committed Mar 28, 2022
1 parent 67bb323 commit 13b0cda
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 55 deletions.
37 changes: 2 additions & 35 deletions src/libslic3r/GCodeWriter.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "GCodeWriter.hpp"
#include "CustomGCode.hpp"
#include "LocalesUtils.hpp"

#include <boost/lexical_cast.hpp>

Expand All @@ -24,42 +25,8 @@
#define E_NUM(val) PRECISION(val, this->config.gcode_precision_e.value)
namespace Slic3r {

std::string to_string_nozero(double value, int32_t max_precision) {
double intpart;
if (modf(value, &intpart) == 0.0) {
//shortcut for int
return boost::lexical_cast<std::string>(intpart);
} else {
std::stringstream ss;
//first, get the int part, to see how many digit it takes
int long10 = 0;
if (intpart > 9)
long10 = (int)std::floor(std::log10(std::abs(intpart)));
//set the usable precision: there is only 15-16 decimal digit in a double
ss << std::fixed << std::setprecision(int(std::min(15 - long10, int(max_precision)))) << value;
std::string ret = ss.str();
uint8_t nb_del = 0;
if (ret.find('.') != std::string::npos) {
uint8_t idx_char;
for (idx_char = uint8_t(ss.tellp()) - 1; idx_char > 0; idx_char--) {
if (ret[idx_char] == '0')
nb_del++;
else
break;
}
// remove the '.' at the end of the int
if (idx_char > 0 && ret[idx_char] == '.')
nb_del++;
}

if (nb_del > 0)
return ret.substr(0, ret.size() - nb_del);
else
return ret;
}
}

std::string GCodeWriter::PausePrintCode = "M601";
std::string GCodeWriter::PausePrintCode = "M601";

void GCodeWriter::apply_print_config(const PrintConfig &print_config)
{
Expand Down
79 changes: 59 additions & 20 deletions src/libslic3r/LocalesUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,28 +61,67 @@ double string_to_double_decimal_point(const std::string_view str, size_t* pos /*
return out;
}

std::string to_string_nozero(double value, int32_t max_precision) {
double intpart;
if (modf(value, &intpart) == 0.0) {
//shortcut for int
return boost::lexical_cast<std::string>(intpart);
} else {
std::stringstream ss;
//first, get the int part, to see how many digit it takes
int long10 = 0;
if (intpart > 9)
long10 = (int)std::floor(std::log10(std::abs(intpart)));
//set the usable precision: there is only 15-16 decimal digit in a double
ss << std::fixed << std::setprecision(int(std::min(15 - long10, int(max_precision)))) << value;
std::string ret = ss.str();
uint8_t nb_del = 0;
if (ret.find('.') != std::string::npos) {
uint8_t idx_char;
for (idx_char = uint8_t(ss.tellp()) - 1; idx_char > 0; idx_char--) {
if (ret[idx_char] == '0')
nb_del++;
else
break;
}
// remove the '.' at the end of the int
if (idx_char > 0 && ret[idx_char] == '.')
nb_del++;
}

if (nb_del > 0)
return ret.substr(0, ret.size() - nb_del);
else
return ret;
}
}

std::string float_to_string_decimal_point(double value, int precision/* = -1*/)
{
// Our Windows build server fully supports C++17 std::to_chars. Let's use it.
// Other platforms are behind, fall back to slow stringstreams for now.
#ifdef _WIN32
constexpr size_t SIZE = 20;
char out[SIZE] = "";
std::to_chars_result res;
if (precision >=0)
res = std::to_chars(out, out+SIZE, value, std::chars_format::fixed, precision);
else
res = std::to_chars(out, out+SIZE, value, std::chars_format::general, 6);
if (res.ec == std::errc::value_too_large)
throw std::invalid_argument("float_to_string_decimal_point conversion failed.");
return std::string(out, res.ptr - out);
#else
std::stringstream buf;
if (precision >= 0)
buf << std::fixed << std::setprecision(precision);
buf << value;
return buf.str();
#endif
// merill: this fail on 'float_to_string_decimal_point(0.2)' because the 0.2 is a 0.200000001 (from a float->double conversion probably)
// so i revert this to my slow but trusty to_string_nozero
// // Our Windows build server fully supports C++17 std::to_chars. Let's use it.
// // Other platforms are behind, fall back to slow stringstreams for now.
//#ifdef _WIN32
// constexpr size_t SIZE = 20;
// char out[SIZE] = "";
// std::to_chars_result res;
// if (precision >=0)
// res = std::to_chars(out, out+SIZE, value, std::chars_format::fixed, precision);
// else
// res = std::to_chars(out, out+SIZE, value, std::chars_format::general, 6);
// if (res.ec == std::errc::value_too_large)
// throw std::invalid_argument("float_to_string_decimal_point conversion failed.");
// return std::string(out, res.ptr - out);
//#else
// std::stringstream buf;
// if (precision >= 0)
// buf << std::fixed << std::setprecision(precision);
// buf << value;
// return buf.str();
//#endif

return to_string_nozero(value, precision < 0 ? 6 : precision);
}


Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/LocalesUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class CNumericLocalesSetter {
bool is_decimal_separator_point();


std::string to_string_nozero(double value, int32_t max_precision);

// A substitute for std::to_string that works according to
// C++ locales, not C locale. Meant to be used when we need
// to be sure that decimal point is used as a separator.
Expand Down

0 comments on commit 13b0cda

Please sign in to comment.