]> git.lyx.org Git - lyx.git/commitdiff
Introduce proper integer rounding function
authorGeorg Baum <baum@lyx.org>
Wed, 17 Feb 2016 20:31:37 +0000 (21:31 +0100)
committerGeorg Baum <baum@lyx.org>
Wed, 17 Feb 2016 20:42:37 +0000 (21:42 +0100)
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.

src/Length.cpp
src/insets/InsetGraphics.cpp
src/mathed/InsetMathChar.cpp
src/mathed/InsetMathSymbol.cpp
src/support/lstrings.cpp
src/support/lyxlib.h

index 44c3c8137161d1ace6f0c31c316ad8fa46f979f8..d862f40213d3a4bdea1e834bc0f3cf586d1b1616 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "support/docstream.h"
 #include "support/lstrings.h"
+#include "support/lyxlib.h"
 
 #include <sstream>
 #include <iomanip>
@@ -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<int>(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<int>(result + 0.5);
+       return support::iround(result);
 }
 
 
index 555ece14252e47d992bcc976dca9477e177f94a3..323eaacd6b2966236ac7b4fe040de057d25c1bbd 100644 (file)
@@ -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<int>( (scl) + 0.5 )
+                               << support::iround(scl)
                                << "\" ";
        } else {
                if (!params().width.zero()) {
index 558bcd1c6ee88675d92e6e168db7805f283f6487..713e1353e683ee9cff9460285b0cc7e8e36e1afa 100644 (file)
@@ -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<int>(0.5*em+0.5);
+               dim.wid += support::iround(0.5 * em);
        else if (char_ == '\'')
-               dim.wid += static_cast<int>(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<int>(0.25*em+0.5);
+               x += support::iround(0.25 * em);
        else if (char_ == '\'')
-               x += static_cast<int>(0.0833*em+0.5);
+               x += support::iround(0.0833 * em);
 #if 1
        if (char_ == '=' && has_math_fonts) {
                FontSetChanger dummy(pi.base, "cmr");
index 352352bdd66d2c937a9feff31fd4d17cef48015e..a160dec684883a5cb31f099b6b9615130cd5ed76 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "support/debug.h"
 #include "support/docstream.h"
+#include "support/lyxlib.h"
 #include "support/textutils.h"
 
 #include <boost/scoped_ptr.hpp>
@@ -80,9 +81,9 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const
        }
        // seperate things a bit
        if (isRelOp())
-               dim.wid += static_cast<int>(0.5 * em + 0.5);
+               dim.wid += support::iround(0.5 * em);
        else
-               dim.wid += static_cast<int>(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<int>(0.25*em+0.5);
+               x += support::iround(0.25 * em);
        else
-               x += static_cast<int>(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);
index d06458bd815c9703ac1746216bc5d57c5abfa8e8..f4aba23c0a530d7c7e0aa4617b0950835776b875 100644 (file)
 
 #include "support/convert.h"
 #include "support/debug.h"
+#include "support/lyxlib.h"
 #include "support/qstring_helpers.h"
 
 #include "support/lassert.h"
 
 #include <QString>
 
-#include <cmath>
 #include <cstdio>
 #include <cstring>
 #include <algorithm>
@@ -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<int>(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");
index 287a707e49519750c745c7680e6e83b838d218a5..23894ee2ebea1d47d077ca3344ada70edd32e89f 100644 (file)
 #ifndef LYX_LIB_H
 #define LYX_LIB_H
 
+// always include <math.h> (also with MSVC), to avoid compiler specific side effects
+#include <math.h>
+
+#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<int>(round(x));
+}
+
 } // namespace support
 } // namespace lyx