From: Georg Baum Date: Wed, 17 Feb 2016 20:31:37 +0000 (+0100) Subject: Introduce proper integer rounding function X-Git-Tag: 2.2.0rc1~145 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=c0ce79452f0d286255bcbdf04b8d601a9a734e8d;p=lyx.git Introduce proper integer rounding function This fixes a failing unit test with 32bit gcc 4.9.3 and -O2 optimization: It computed 9953 instead of 9954 for Length::inPixels() of value 2342. The reason for this is probably different rounding behaviour caused by storing the unrounded value in a processor register (uses 80bit accuracy) vs. writing it back to memory (uses 64bit accuracy). The unrounded value is very close to 9953.5 (which is not representable as an exact IEEE floating point value). Apart from that, having a proper function for rounding makes the code more readable, and has the nice side effect to make Length::inPB() work for negative lengths as well. --- diff --git a/src/Length.cpp b/src/Length.cpp index 44c3c81371..d862f40213 100644 --- a/src/Length.cpp +++ b/src/Length.cpp @@ -23,6 +23,7 @@ #include "support/docstream.h" #include "support/lstrings.h" +#include "support/lyxlib.h" #include #include @@ -215,7 +216,7 @@ int Length::inPixels(int text_width, int em_width_base) const double const text_width_in = text_width / (zoom * dpi); double const result = zoom * dpi * inInch(text_width_in, em_width_in); - return static_cast(result + ((result >= 0) ? 0.5 : -0.5)); + return support::iround(result); } @@ -311,7 +312,7 @@ int Length::inBP() const double const text_width_in = 210.0 / 2.54; // assume A4 double const em_width_in = 10.0 / 72.27; double result = 72.0 * inInch(text_width_in, em_width_in); - return static_cast(result + 0.5); + return support::iround(result); } diff --git a/src/insets/InsetGraphics.cpp b/src/insets/InsetGraphics.cpp index 555ece1425..323eaacd6b 100644 --- a/src/insets/InsetGraphics.cpp +++ b/src/insets/InsetGraphics.cpp @@ -438,7 +438,7 @@ docstring InsetGraphics::createDocBookAttributes() const if (!params().scale.empty() && !float_equal(scl, 0.0, 0.05)) { if (!float_equal(scl, 100.0, 0.05)) options << " scale=\"" - << static_cast( (scl) + 0.5 ) + << support::iround(scl) << "\" "; } else { if (!params().width.zero()) { diff --git a/src/mathed/InsetMathChar.cpp b/src/mathed/InsetMathChar.cpp index 558bcd1c6e..713e1353e6 100644 --- a/src/mathed/InsetMathChar.cpp +++ b/src/mathed/InsetMathChar.cpp @@ -26,6 +26,7 @@ #include "support/debug.h" #include "support/lstrings.h" +#include "support/lyxlib.h" #include "support/textutils.h" @@ -77,9 +78,9 @@ void InsetMathChar::metrics(MetricsInfo & mi, Dimension & dim) const } int const em = mathed_font_em(mi.base.font); if (isBinaryOp(char_)) - dim.wid += static_cast(0.5*em+0.5); + dim.wid += support::iround(0.5 * em); else if (char_ == '\'') - dim.wid += static_cast(0.1667*em+0.5); + dim.wid += support::iround(0.1667 * em); #else whichFont(font_, code_, mi); dim = theFontMetrics(font_).dimension(char_); @@ -95,9 +96,9 @@ void InsetMathChar::draw(PainterInfo & pi, int x, int y) const //lyxerr << "drawing '" << char_ << "' font: " << pi.base.fontname << std::endl; int const em = mathed_font_em(pi.base.font); if (isBinaryOp(char_)) - x += static_cast(0.25*em+0.5); + x += support::iround(0.25 * em); else if (char_ == '\'') - x += static_cast(0.0833*em+0.5); + x += support::iround(0.0833 * em); #if 1 if (char_ == '=' && has_math_fonts) { FontSetChanger dummy(pi.base, "cmr"); diff --git a/src/mathed/InsetMathSymbol.cpp b/src/mathed/InsetMathSymbol.cpp index 352352bdd6..a160dec684 100644 --- a/src/mathed/InsetMathSymbol.cpp +++ b/src/mathed/InsetMathSymbol.cpp @@ -21,6 +21,7 @@ #include "support/debug.h" #include "support/docstream.h" +#include "support/lyxlib.h" #include "support/textutils.h" #include @@ -80,9 +81,9 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const } // seperate things a bit if (isRelOp()) - dim.wid += static_cast(0.5 * em + 0.5); + dim.wid += support::iround(0.5 * em); else - dim.wid += static_cast(0.1667 * em + 0.5); + dim.wid += support::iround(0.1667 * em); scriptable_ = false; if (mi.base.style == LM_ST_DISPLAY) @@ -106,9 +107,9 @@ void InsetMathSymbol::draw(PainterInfo & pi, int x, int y) const std::string const font = italic_upcase_greek ? "cmm" : sym_->inset; int const em = mathed_font_em(pi.base.font); if (isRelOp()) - x += static_cast(0.25*em+0.5); + x += support::iround(0.25 * em); else - x += static_cast(0.0833*em+0.5); + x += support::iround(0.0833 * em); FontSetChanger dummy(pi.base, from_ascii(font)); pi.draw(x, y - h_, sym_->draw); diff --git a/src/support/lstrings.cpp b/src/support/lstrings.cpp index d06458bd81..f4aba23c0a 100644 --- a/src/support/lstrings.cpp +++ b/src/support/lstrings.cpp @@ -16,13 +16,13 @@ #include "support/convert.h" #include "support/debug.h" +#include "support/lyxlib.h" #include "support/qstring_helpers.h" #include "support/lassert.h" #include -#include #include #include #include @@ -1400,18 +1400,6 @@ int findToken(char const * const str[], string const & search_token) } -#ifdef _MSC_VER -// Replacement for C99 function lround() -double round(double x) -{ - if (x < 0) - return ceil(x - 0.5); - else - return floor(x + 0.5); -} -#endif - - std::string formatFPNumber(double x) { // Need manual tweaking, QString::number(x, 'f', 16) does not work either @@ -1420,7 +1408,7 @@ std::string formatFPNumber(double x) // Prevent outputs of 23.4200000000000017 but output small numbers // with at least 6 significant digits. double const logarithm = log10(fabs(x)); - os << std::setprecision(max(6 - static_cast(round(logarithm)), 0)) << x; + os << std::setprecision(max(6 - iround(logarithm), 0)) << x; string result = os.str(); if (result.find('.') != string::npos) { result = rtrim(result, "0"); diff --git a/src/support/lyxlib.h b/src/support/lyxlib.h index 287a707e49..23894ee2eb 100644 --- a/src/support/lyxlib.h +++ b/src/support/lyxlib.h @@ -15,6 +15,20 @@ #ifndef LYX_LIB_H #define LYX_LIB_H +// always include (also with MSVC), to avoid compiler specific side effects +#include + +#ifdef _MSC_VER +/// Replacement for C99 round() +inline double round(double x) +{ + if (x < 0) + return ceil(x - 0.5); + else + return floor(x + 0.5); +} +#endif + namespace lyx { namespace support { @@ -34,6 +48,12 @@ inline bool float_equal(double var, double number, double error) return (number - error <= var && var <= number + error); } +/// round \p x to nearest integer +inline int iround(double x) +{ + return static_cast(round(x)); +} + } // namespace support } // namespace lyx