mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-16 19:54:38 +01:00
fixed GH #1128: Poco::NumberFormatter::format(float, precision) rounding changed
This commit is contained in:
parent
2c6a74c4f5
commit
4e85aa4df2
@ -208,6 +208,15 @@ public:
|
||||
/// Formats a float value in decimal floating-point notation,
|
||||
/// according to std::printf's %g format with a precision of 8 fractional digits.
|
||||
|
||||
static std::string format(float value, int precision);
|
||||
/// Formats a double value in decimal floating-point notation,
|
||||
/// according to std::printf's %f format with the given precision.
|
||||
|
||||
static std::string format(float value, int width, int precision);
|
||||
/// Formats a double value in decimal floating-point notation,
|
||||
/// right justified in a field of the specified width,
|
||||
/// with the number of fractional digits given in precision.
|
||||
|
||||
static std::string format(double value);
|
||||
/// Formats a double value in decimal floating-point notation,
|
||||
/// according to std::printf's %g format with a precision of 16 fractional digits.
|
||||
@ -368,6 +377,15 @@ public:
|
||||
/// Formats a float value in decimal floating-point notation,
|
||||
/// according to std::printf's %g format with a precision of 8 fractional digits.
|
||||
|
||||
static void append(std::string& str, float value, int precision);
|
||||
/// Formats a double value in decimal floating-point notation,
|
||||
/// according to std::printf's %f format with the given precision.
|
||||
|
||||
static void append(std::string& str, float value, int width, int precision);
|
||||
/// Formats a double value in decimal floating-point notation,
|
||||
/// right justified in a field of the specified width,
|
||||
/// with the number of fractional digits given in precision.
|
||||
|
||||
static void append(std::string& str, double value);
|
||||
/// Formats a double value in decimal floating-point notation,
|
||||
/// according to std::printf's %g format with a precision of 16 fractional digits.
|
||||
@ -641,33 +659,49 @@ inline std::string NumberFormatter::formatHex(UInt64 value, int width, bool pref
|
||||
|
||||
|
||||
inline std::string NumberFormatter::format(float value)
|
||||
{
|
||||
char buffer[POCO_MAX_FLT_STRING_LEN];
|
||||
floatToStr(buffer, POCO_MAX_FLT_STRING_LEN, value);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
|
||||
inline std::string NumberFormatter::format(float value, int precision)
|
||||
{
|
||||
char buffer[POCO_MAX_FLT_STRING_LEN];
|
||||
floatToFixedStr(buffer, POCO_MAX_FLT_STRING_LEN, value, precision);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
|
||||
inline std::string NumberFormatter::format(float value, int width, int precision)
|
||||
{
|
||||
std::string result;
|
||||
floatToStr(result, value);
|
||||
floatToFixedStr(result, value, precision, width);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
inline std::string NumberFormatter::format(double value)
|
||||
{
|
||||
std::string result;
|
||||
doubleToStr(result, value);
|
||||
return result;
|
||||
char buffer[POCO_MAX_FLT_STRING_LEN];
|
||||
doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, value);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
|
||||
inline std::string NumberFormatter::format(double value, int precision)
|
||||
{
|
||||
std::string result;
|
||||
doubleToStr(result, value, precision);
|
||||
return result;
|
||||
char buffer[POCO_MAX_FLT_STRING_LEN];
|
||||
doubleToFixedStr(buffer, POCO_MAX_FLT_STRING_LEN, value, precision);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
|
||||
inline std::string NumberFormatter::format(double value, int width, int precision)
|
||||
{
|
||||
std::string result;
|
||||
doubleToStr(result, value, precision, width);
|
||||
doubleToFixedStr(result, value, precision, width);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
|
||||
// binary numbers are supported, thus 64 (bits) + 1 (string terminating zero)
|
||||
#define POCO_MAX_INT_STRING_LEN 65
|
||||
// value from strtod.cc (double_conversion::kMaxSignificantDecimalDigits)
|
||||
@ -441,16 +442,25 @@ bool uIntToStr (T number, unsigned short base, std::string& result, bool prefix
|
||||
// http://florian.loitsch.com/publications/dtoa-pldi2010.pdf
|
||||
//
|
||||
|
||||
|
||||
Foundation_API void floatToStr(char* buffer,
|
||||
int bufferSize,
|
||||
float value,
|
||||
int lowDec = -std::numeric_limits<double>::digits10,
|
||||
int highDec = std::numeric_limits<double>::digits10);
|
||||
int lowDec = -std::numeric_limits<float>::digits10,
|
||||
int highDec = std::numeric_limits<float>::digits10);
|
||||
/// Converts a float value to string. Converted string must be shorter than bufferSize.
|
||||
/// Conversion is done by computing the shortest string of digits that correctly represents
|
||||
/// the input number. Depending on lowDec and highDec values, the function returns
|
||||
/// decimal or exponential representation.
|
||||
|
||||
Foundation_API void floatToFixedStr(char* buffer,
|
||||
int bufferSize,
|
||||
float value,
|
||||
int precision);
|
||||
/// Converts a float value to string. Converted string must be shorter than bufferSize.
|
||||
/// Computes a decimal representation with a fixed number of digits after the
|
||||
/// decimal point.
|
||||
|
||||
|
||||
Foundation_API std::string& floatToStr(std::string& str,
|
||||
float value,
|
||||
@ -464,6 +474,17 @@ Foundation_API std::string& floatToStr(std::string& str,
|
||||
/// and width (total length of formatted string).
|
||||
|
||||
|
||||
Foundation_API std::string& floatToFixedStr(std::string& str,
|
||||
float value,
|
||||
int precision,
|
||||
int width = 0,
|
||||
char thSep = 0,
|
||||
char decSep = 0);
|
||||
/// Converts a float value, assigns it to the supplied string and returns the reference.
|
||||
/// This function calls floatToFixedStr(char*, int, float, int) and formats the result according to
|
||||
/// precision (total number of digits after the decimal point) and width (total length of formatted string).
|
||||
|
||||
|
||||
Foundation_API void doubleToStr(char* buffer,
|
||||
int bufferSize,
|
||||
double value,
|
||||
@ -475,6 +496,15 @@ Foundation_API void doubleToStr(char* buffer,
|
||||
/// decimal or exponential representation.
|
||||
|
||||
|
||||
Foundation_API void doubleToFixedStr(char* buffer,
|
||||
int bufferSize,
|
||||
double value,
|
||||
int precision);
|
||||
/// Converts a double value to string. Converted string must be shorter than bufferSize.
|
||||
/// Computes a decimal representation with a fixed number of digits after the
|
||||
/// decimal point.
|
||||
|
||||
|
||||
Foundation_API std::string& doubleToStr(std::string& str,
|
||||
double value,
|
||||
int precision = -1,
|
||||
@ -482,11 +512,22 @@ Foundation_API std::string& doubleToStr(std::string& str,
|
||||
char thSep = 0,
|
||||
char decSep = 0);
|
||||
/// Converts a double value, assigns it to the supplied string and returns the reference.
|
||||
/// This function calls doubleToStr(char*, int, float, int, int) and formats the result according to
|
||||
/// This function calls doubleToStr(char*, int, double, int, int) and formats the result according to
|
||||
/// precision (total number of digits after the decimal point, -1 means ignore precision argument)
|
||||
/// and width (total length of formatted string).
|
||||
|
||||
|
||||
Foundation_API std::string& doubleToFixedStr(std::string& str,
|
||||
double value,
|
||||
int precision = -1,
|
||||
int width = 0,
|
||||
char thSep = 0,
|
||||
char decSep = 0);
|
||||
/// Converts a double value, assigns it to the supplied string and returns the reference.
|
||||
/// This function calls doubleToFixedStr(char*, int, double, int) and formats the result according to
|
||||
/// precision (total number of digits after the decimal point) and width (total length of formatted string).
|
||||
|
||||
|
||||
Foundation_API float strToFloat(const char* str);
|
||||
/// Converts the string of characters into single-precision floating point number.
|
||||
/// Function uses double_convesrion::DoubleToStringConverter to do the conversion.
|
||||
@ -513,10 +554,6 @@ Foundation_API bool strToDouble(const std::string& str, double& result, char dec
|
||||
///
|
||||
/// Returns true if successful, false otherwise.
|
||||
|
||||
//
|
||||
// end double-conversion functions declarations
|
||||
//
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
@ -340,6 +340,21 @@ void NumberFormatter::append(std::string& str, float value)
|
||||
}
|
||||
|
||||
|
||||
void NumberFormatter::append(std::string& str, float value, int precision)
|
||||
{
|
||||
char buffer[NF_MAX_FLT_STRING_LEN];
|
||||
floatToFixedStr(buffer, POCO_MAX_FLT_STRING_LEN, value, precision);
|
||||
str.append(buffer);
|
||||
}
|
||||
|
||||
|
||||
void NumberFormatter::append(std::string& str, float value, int width, int precision)
|
||||
{
|
||||
std::string result;
|
||||
str.append(floatToFixedStr(result, value, precision, width));
|
||||
}
|
||||
|
||||
|
||||
void NumberFormatter::append(std::string& str, double value)
|
||||
{
|
||||
char buffer[NF_MAX_FLT_STRING_LEN];
|
||||
@ -350,15 +365,16 @@ void NumberFormatter::append(std::string& str, double value)
|
||||
|
||||
void NumberFormatter::append(std::string& str, double value, int precision)
|
||||
{
|
||||
std::string result;
|
||||
str.append(doubleToStr(result, value, precision));
|
||||
char buffer[NF_MAX_FLT_STRING_LEN];
|
||||
doubleToFixedStr(buffer, POCO_MAX_FLT_STRING_LEN, value, precision);
|
||||
str.append(buffer);
|
||||
}
|
||||
|
||||
|
||||
void NumberFormatter::append(std::string& str, double value, int width, int precision)
|
||||
{
|
||||
std::string result;
|
||||
str.append(doubleToStr(result, value, precision, width));
|
||||
str.append(doubleToFixedStr(result, value, precision, width));
|
||||
}
|
||||
|
||||
|
||||
|
@ -140,6 +140,19 @@ void floatToStr(char* buffer, int bufferSize, float value, int lowDec, int highD
|
||||
}
|
||||
|
||||
|
||||
void floatToFixedStr(char* buffer, int bufferSize, float value, int precision)
|
||||
{
|
||||
using namespace double_conversion;
|
||||
|
||||
StringBuilder builder(buffer, bufferSize);
|
||||
int flags = DoubleToStringConverter::UNIQUE_ZERO |
|
||||
DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;
|
||||
DoubleToStringConverter dc(flags, POCO_FLT_INF, POCO_FLT_NAN, POCO_FLT_EXP, -std::numeric_limits<float>::digits10, std::numeric_limits<float>::digits10, 0, 0);
|
||||
dc.ToFixed(value, precision, &builder);
|
||||
builder.Finalize();
|
||||
}
|
||||
|
||||
|
||||
std::string& floatToStr(std::string& str, float value, int precision, int width, char thSep, char decSep)
|
||||
{
|
||||
if (!decSep) decSep = '.';
|
||||
@ -158,6 +171,24 @@ std::string& floatToStr(std::string& str, float value, int precision, int width,
|
||||
}
|
||||
|
||||
|
||||
std::string& floatToFixedStr(std::string& str, float value, int precision, int width, char thSep, char decSep)
|
||||
{
|
||||
if (!decSep) decSep = '.';
|
||||
if (precision == 0) value = std::floor(value);
|
||||
|
||||
char buffer[POCO_MAX_FLT_STRING_LEN];
|
||||
floatToFixedStr(buffer, POCO_MAX_FLT_STRING_LEN, value, precision);
|
||||
str = buffer;
|
||||
|
||||
if (decSep && (decSep != '.') && (str.find('.') != std::string::npos))
|
||||
replaceInPlace(str, '.', decSep);
|
||||
|
||||
if (thSep) insertThousandSep(str, thSep, decSep);
|
||||
if (precision > 0 || width) pad(str, precision, width, ' ', decSep ? decSep : '.');
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
void doubleToStr(char* buffer, int bufferSize, double value, int lowDec, int highDec)
|
||||
{
|
||||
using namespace double_conversion;
|
||||
@ -171,6 +202,19 @@ void doubleToStr(char* buffer, int bufferSize, double value, int lowDec, int hig
|
||||
}
|
||||
|
||||
|
||||
void doubleToFixedStr(char* buffer, int bufferSize, double value, int precision)
|
||||
{
|
||||
using namespace double_conversion;
|
||||
|
||||
StringBuilder builder(buffer, bufferSize);
|
||||
int flags = DoubleToStringConverter::UNIQUE_ZERO |
|
||||
DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;
|
||||
DoubleToStringConverter dc(flags, POCO_FLT_INF, POCO_FLT_NAN, POCO_FLT_EXP, -std::numeric_limits<double>::digits10, std::numeric_limits<double>::digits10, 0, 0);
|
||||
dc.ToFixed(value, precision, &builder);
|
||||
builder.Finalize();
|
||||
}
|
||||
|
||||
|
||||
std::string& doubleToStr(std::string& str, double value, int precision, int width, char thSep, char decSep)
|
||||
{
|
||||
if (!decSep) decSep = '.';
|
||||
@ -178,6 +222,26 @@ std::string& doubleToStr(std::string& str, double value, int precision, int widt
|
||||
|
||||
char buffer[POCO_MAX_FLT_STRING_LEN];
|
||||
doubleToStr(buffer, POCO_MAX_FLT_STRING_LEN, value);
|
||||
|
||||
str = buffer;
|
||||
|
||||
if (decSep && (decSep != '.') && (str.find('.') != std::string::npos))
|
||||
replaceInPlace(str, '.', decSep);
|
||||
|
||||
if (thSep) insertThousandSep(str, thSep, decSep);
|
||||
if (precision > 0 || width) pad(str, precision, width, ' ', decSep ? decSep : '.');
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
std::string& doubleToFixedStr(std::string& str, double value, int precision, int width, char thSep, char decSep)
|
||||
{
|
||||
if (!decSep) decSep = '.';
|
||||
if (precision == 0) value = std::floor(value);
|
||||
|
||||
char buffer[POCO_MAX_FLT_STRING_LEN];
|
||||
doubleToFixedStr(buffer, POCO_MAX_FLT_STRING_LEN, value, precision);
|
||||
|
||||
str = buffer;
|
||||
|
||||
if (decSep && (decSep != '.') && (str.find('.') != std::string::npos))
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "Poco/NumberFormatter.h"
|
||||
#include <sstream>
|
||||
|
||||
|
||||
using Poco::NumberFormatter;
|
||||
using Poco::Int64;
|
||||
using Poco::UInt64;
|
||||
@ -208,11 +209,13 @@ void NumberFormatterTest::testFormatFloat()
|
||||
assert(NumberFormatter::format(12.25, 4) == "12.2500");
|
||||
assert(NumberFormatter::format(12.25, 8, 4) == " 12.2500");
|
||||
|
||||
assert (NumberFormatter::format(12.45f, 2) == "12.45");
|
||||
|
||||
assert(NumberFormatter::format(-12.25) == "-12.25");
|
||||
assert(NumberFormatter::format(-12.25, 4) == "-12.2500");
|
||||
assert(NumberFormatter::format(-12.25, 10, 4) == " -12.2500");
|
||||
assert(NumberFormatter::format(-12.25, 10, 2) == " -12.25");
|
||||
|
||||
assert(NumberFormatter::format(-12.25, 10, 1) == " -12.3");
|
||||
|
||||
assert (NumberFormatter::format(50.0, 3) == "50.000");
|
||||
assert (NumberFormatter::format(50.0f, 3) == "50.000");
|
||||
@ -220,8 +223,9 @@ void NumberFormatterTest::testFormatFloat()
|
||||
assert (NumberFormatter::format(50.123f, 3) == "50.123");
|
||||
assert (NumberFormatter::format(50.123, 0) == "50");
|
||||
assert (NumberFormatter::format(50.123f, 0) == "50");
|
||||
assert (NumberFormatter::format(50.546, 0) == "50");
|
||||
assert (NumberFormatter::format(50.546f, 0) == "50");
|
||||
assert (NumberFormatter::format(50.546, 0) == "51");
|
||||
assert (NumberFormatter::format(50.546f, 0) == "51");
|
||||
assert (NumberFormatter::format(50.546f, 2) == "50.55");
|
||||
}
|
||||
|
||||
|
||||
@ -258,7 +262,7 @@ void NumberFormatterTest::testAppend()
|
||||
assert (s == "123.4");
|
||||
s.erase();
|
||||
NumberFormatter::append(s, 123.4567, 2);
|
||||
assert (s == "123.45");
|
||||
assert (s == "123.46");
|
||||
s.erase();
|
||||
NumberFormatter::append(s, 123.4567, 10, 5);
|
||||
assert (s == " 123.45670");
|
||||
@ -269,7 +273,7 @@ void NumberFormatterTest::testAppend()
|
||||
NumberFormatter::append(s, static_cast<double>(1234567), 2);
|
||||
assert (s == "1234567.00");
|
||||
s.erase();
|
||||
NumberFormatter::append(s, 1234567, 10, 1);
|
||||
NumberFormatter::append(s, 1234567.0, 10, 1);
|
||||
assert (s == " 1234567.0");
|
||||
}
|
||||
|
||||
|
@ -930,7 +930,6 @@ void StringTest::testIntToString()
|
||||
assert (result == "11110000111100001111000011110000");
|
||||
#if defined(POCO_HAVE_INT64)
|
||||
assert (uIntToStr(0xFFFFFFFFFFFFFFFF, 2, result));
|
||||
std::cout << 0xFFFFFFFFFFFFFFFF << std::endl;
|
||||
assert (result == "1111111111111111111111111111111111111111111111111111111111111111");
|
||||
assert (uIntToStr(0xFF00000FF00000FF, 2, result));
|
||||
assert (result == "1111111100000000000000000000111111110000000000000000000011111111");
|
||||
|
Loading…
Reference in New Issue
Block a user