mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-25 19:07:45 +00:00
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.
This commit is contained in:
parent
fc459bd977
commit
c0ce79452f
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "support/docstream.h"
|
#include "support/docstream.h"
|
||||||
#include "support/lstrings.h"
|
#include "support/lstrings.h"
|
||||||
|
#include "support/lyxlib.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#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 text_width_in = text_width / (zoom * dpi);
|
||||||
double const result = zoom * dpi * inInch(text_width_in, em_width_in);
|
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 text_width_in = 210.0 / 2.54; // assume A4
|
||||||
double const em_width_in = 10.0 / 72.27;
|
double const em_width_in = 10.0 / 72.27;
|
||||||
double result = 72.0 * inInch(text_width_in, em_width_in);
|
double result = 72.0 * inInch(text_width_in, em_width_in);
|
||||||
return static_cast<int>(result + 0.5);
|
return support::iround(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ docstring InsetGraphics::createDocBookAttributes() const
|
|||||||
if (!params().scale.empty() && !float_equal(scl, 0.0, 0.05)) {
|
if (!params().scale.empty() && !float_equal(scl, 0.0, 0.05)) {
|
||||||
if (!float_equal(scl, 100.0, 0.05))
|
if (!float_equal(scl, 100.0, 0.05))
|
||||||
options << " scale=\""
|
options << " scale=\""
|
||||||
<< static_cast<int>( (scl) + 0.5 )
|
<< support::iround(scl)
|
||||||
<< "\" ";
|
<< "\" ";
|
||||||
} else {
|
} else {
|
||||||
if (!params().width.zero()) {
|
if (!params().width.zero()) {
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include "support/debug.h"
|
#include "support/debug.h"
|
||||||
#include "support/lstrings.h"
|
#include "support/lstrings.h"
|
||||||
|
#include "support/lyxlib.h"
|
||||||
#include "support/textutils.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);
|
int const em = mathed_font_em(mi.base.font);
|
||||||
if (isBinaryOp(char_))
|
if (isBinaryOp(char_))
|
||||||
dim.wid += static_cast<int>(0.5*em+0.5);
|
dim.wid += support::iround(0.5 * em);
|
||||||
else if (char_ == '\'')
|
else if (char_ == '\'')
|
||||||
dim.wid += static_cast<int>(0.1667*em+0.5);
|
dim.wid += support::iround(0.1667 * em);
|
||||||
#else
|
#else
|
||||||
whichFont(font_, code_, mi);
|
whichFont(font_, code_, mi);
|
||||||
dim = theFontMetrics(font_).dimension(char_);
|
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;
|
//lyxerr << "drawing '" << char_ << "' font: " << pi.base.fontname << std::endl;
|
||||||
int const em = mathed_font_em(pi.base.font);
|
int const em = mathed_font_em(pi.base.font);
|
||||||
if (isBinaryOp(char_))
|
if (isBinaryOp(char_))
|
||||||
x += static_cast<int>(0.25*em+0.5);
|
x += support::iround(0.25 * em);
|
||||||
else if (char_ == '\'')
|
else if (char_ == '\'')
|
||||||
x += static_cast<int>(0.0833*em+0.5);
|
x += support::iround(0.0833 * em);
|
||||||
#if 1
|
#if 1
|
||||||
if (char_ == '=' && has_math_fonts) {
|
if (char_ == '=' && has_math_fonts) {
|
||||||
FontSetChanger dummy(pi.base, "cmr");
|
FontSetChanger dummy(pi.base, "cmr");
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "support/debug.h"
|
#include "support/debug.h"
|
||||||
#include "support/docstream.h"
|
#include "support/docstream.h"
|
||||||
|
#include "support/lyxlib.h"
|
||||||
#include "support/textutils.h"
|
#include "support/textutils.h"
|
||||||
|
|
||||||
#include <boost/scoped_ptr.hpp>
|
#include <boost/scoped_ptr.hpp>
|
||||||
@ -80,9 +81,9 @@ void InsetMathSymbol::metrics(MetricsInfo & mi, Dimension & dim) const
|
|||||||
}
|
}
|
||||||
// seperate things a bit
|
// seperate things a bit
|
||||||
if (isRelOp())
|
if (isRelOp())
|
||||||
dim.wid += static_cast<int>(0.5 * em + 0.5);
|
dim.wid += support::iround(0.5 * em);
|
||||||
else
|
else
|
||||||
dim.wid += static_cast<int>(0.1667 * em + 0.5);
|
dim.wid += support::iround(0.1667 * em);
|
||||||
|
|
||||||
scriptable_ = false;
|
scriptable_ = false;
|
||||||
if (mi.base.style == LM_ST_DISPLAY)
|
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;
|
std::string const font = italic_upcase_greek ? "cmm" : sym_->inset;
|
||||||
int const em = mathed_font_em(pi.base.font);
|
int const em = mathed_font_em(pi.base.font);
|
||||||
if (isRelOp())
|
if (isRelOp())
|
||||||
x += static_cast<int>(0.25*em+0.5);
|
x += support::iround(0.25 * em);
|
||||||
else
|
else
|
||||||
x += static_cast<int>(0.0833*em+0.5);
|
x += support::iround(0.0833 * em);
|
||||||
|
|
||||||
FontSetChanger dummy(pi.base, from_ascii(font));
|
FontSetChanger dummy(pi.base, from_ascii(font));
|
||||||
pi.draw(x, y - h_, sym_->draw);
|
pi.draw(x, y - h_, sym_->draw);
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
#include "support/convert.h"
|
#include "support/convert.h"
|
||||||
#include "support/debug.h"
|
#include "support/debug.h"
|
||||||
|
#include "support/lyxlib.h"
|
||||||
#include "support/qstring_helpers.h"
|
#include "support/qstring_helpers.h"
|
||||||
|
|
||||||
#include "support/lassert.h"
|
#include "support/lassert.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <algorithm>
|
#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)
|
std::string formatFPNumber(double x)
|
||||||
{
|
{
|
||||||
// Need manual tweaking, QString::number(x, 'f', 16) does not work either
|
// 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
|
// Prevent outputs of 23.4200000000000017 but output small numbers
|
||||||
// with at least 6 significant digits.
|
// with at least 6 significant digits.
|
||||||
double const logarithm = log10(fabs(x));
|
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();
|
string result = os.str();
|
||||||
if (result.find('.') != string::npos) {
|
if (result.find('.') != string::npos) {
|
||||||
result = rtrim(result, "0");
|
result = rtrim(result, "0");
|
||||||
|
@ -15,6 +15,20 @@
|
|||||||
#ifndef LYX_LIB_H
|
#ifndef LYX_LIB_H
|
||||||
#define 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 lyx {
|
||||||
namespace support {
|
namespace support {
|
||||||
|
|
||||||
@ -34,6 +48,12 @@ inline bool float_equal(double var, double number, double error)
|
|||||||
return (number - error <= var && var <= number + 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 support
|
||||||
} // namespace lyx
|
} // namespace lyx
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user