我需要一个简单的浮点舍入函数,这样:

double round(double);

round(0.1) = 0
round(-0.1) = 0
round(-0.9) = -1

我可以在math.h中找到ceil()和floor() -但没有round()。

它是否以另一个名字出现在标准c++库中,或者它是否丢失了??


当前回答

不需要实现任何东西,所以我不确定为什么这么多答案涉及定义、函数或方法。

C99中

我们有下面的and和header <tgmath.h>用于类型泛型宏。

#include <math.h>
double round (double x);
float roundf (float x);
long double roundl (long double x);

如果您不能编译它,那么您可能遗漏了数学库。类似的命令适用于我拥有的每个C编译器(几个)。

gcc -lm -std=c99 ...

c++ 11

我们在#include <cmath>中有以下和其他依赖于IEEE双精度浮点数的重载。

#include <math.h>
double round (double x);
float round (float x);
long double round (long double x);
double round (T x);

在std名称空间中也有等价物。

如果不能编译,则可能使用C编译而不是c++。下面的基本命令对于g++ 6.3.1、x86_64-w64-mingw32-g++ 6.3.0、clang-x86_64++ 3.8.0和Visual c++ 2015 Community既不会产生错误也不会产生警告。

g++ -std=c++11 -Wall

有序数除法

当除两个序数时,其中T是短的,int,长,或另一个序数,舍入表达式是这样的。

T roundedQuotient = (2 * integerNumerator + 1)
    / (2 * integerDenominator);

精度

毫无疑问,浮点运算中会出现奇怪的错误,但这只是在数字出现时才会出现,与四舍五入无关。

来源不仅仅是IEEE浮点数表示的尾数中的有效数字的数量,它与我们作为人类的十进制思维有关。

10是5和2的乘积,5和2是相对质数。因此,IEEE浮点标准不可能完美地表示为所有二进制数字表示的十进制数。

这不是舍入算法的问题。在选择类型和设计计算、数据输入和数字显示时,应该考虑到数学现实。如果应用程序显示的数字显示了这些十进制-二进制转换问题,那么该应用程序在视觉上表达了数字现实中不存在的、应该更改的准确性。

其他回答

我在asm的x86架构和MS VS特定的c++中使用round的以下实现:

__forceinline int Round(const double v)
{
    int r;
    __asm
    {
        FLD     v
        FISTP   r
        FWAIT
    };
    return r;
}

UPD:返回双值

__forceinline double dround(const double v)
{
    double r;
    __asm
    {
        FLD     v
        FRNDINT
        FSTP    r
        FWAIT
    };
    return r;
}

输出:

dround(0.1): 0.000000000000000
dround(-0.1): -0.000000000000000
dround(0.9): 1.000000000000000
dround(-0.9): -1.000000000000000
dround(1.1): 1.000000000000000
dround(-1.1): -1.000000000000000
dround(0.49999999999999994): 0.000000000000000
dround(-0.49999999999999994): -0.000000000000000
dround(0.5): 0.000000000000000
dround(-0.5): -0.000000000000000

round_f for ARM with math

static inline float round_f(float value)
{
    float rep;
    asm volatile ("vrinta.f32 %0,%1" : "=t"(rep) : "t"(value));
    return rep;
}

没有数学的ARM的round_f

union f__raw {
    struct {
        uint32_t massa  :23;
        uint32_t order  :8;
        uint32_t sign   :1;
    };
    int32_t     i_raw;
    float       f_raw;
};

float round_f(float value)
{
    union f__raw raw;
    int32_t exx;
    uint32_t ex_mask;
    raw.f_raw = value;
    exx = raw.order - 126;
    if (exx < 0) {
        raw.i_raw &= 0x80000000;
    } else if (exx < 24) {
        ex_mask = 0x00ffffff >> exx;
        raw.i_raw += 0x00800000 >> exx;
        if (exx == 0) ex_mask >>= 1;
        raw.i_raw &= ~ex_mask;
    };
    return  raw.f_raw;
};

Boost中还实现了某种类型的舍入:

#include <iostream>

#include <boost/numeric/conversion/converter.hpp>

template<typename T, typename S> T round2(const S& x) {
  typedef boost::numeric::conversion_traits<T, S> Traits;
  typedef boost::numeric::def_overflow_handler OverflowHandler;
  typedef boost::numeric::RoundEven<typename Traits::source_type> Rounder;
  typedef boost::numeric::converter<T, S, Traits, OverflowHandler, Rounder> Converter;
  return Converter::convert(x);
}

int main() {
  std::cout << round2<int, double>(0.1) << ' ' << round2<int, double>(-0.1) << ' ' << round2<int, double>(-0.9) << std::endl;
}

注意,这仅在执行到整数的转换时有效。

Boost提供了一组简单的舍入函数。

#include <boost/math/special_functions/round.hpp>

double a = boost::math::round(1.5); // Yields 2.0
int b = boost::math::iround(1.5); // Yields 2 as an integer

有关更多信息,请参阅Boost文档。

编辑:从c++ 11开始,有std::round, std::lround和std::llround。

从c++ 11开始简单地:

#include <cmath>
std::round(1.1)

或者得到int

static_cast<int>(std::round(1.1))