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

double round(double);

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

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

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


当前回答

小心地板(x+0.5)。下面是在[2^52,2^53]范围内奇数的情况:

-bash-3.2$ cat >test-round.c <<END

#include <math.h>
#include <stdio.h>

int main() {
    double x=5000000000000001.0;
    double y=round(x);
    double z=floor(x+0.5);
    printf("      x     =%f\n",x);
    printf("round(x)    =%f\n",y);
    printf("floor(x+0.5)=%f\n",z);
    return 0;
}
END

-bash-3.2$ gcc test-round.c
-bash-3.2$ ./a.out
      x     =5000000000000001.000000
round(x)    =5000000000000001.000000
floor(x+0.5)=5000000000000002.000000

这里是http://bugs.squeak.org/view.php?id=7134。使用@konik这样的解决方案。

我自己的健壮版本是这样的:

double round(double x)
{
    double truncated,roundedFraction;
    double fraction = modf(x, &truncated);
    modf(2.0*fraction, &roundedFraction);
    return truncated + roundedFraction;
}

这里给出了避免下限(x+0.5)的另一个原因。

其他回答

你可以四舍五入到n位精度:

double round( double x )
{
const double sd = 1000; //for accuracy to 3 decimal places
return int(x*sd + (x<0? -0.5 : 0.5))/sd;
}

我在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;
};

它在cmath中从c++ 11开始提供(根据http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf)

#include <cmath>
#include <iostream>

int main(int argc, char** argv) {
  std::cout << "round(0.5):\t" << round(0.5) << std::endl;
  std::cout << "round(-0.5):\t" << round(-0.5) << std::endl;
  std::cout << "round(1.4):\t" << round(1.4) << std::endl;
  std::cout << "round(-1.4):\t" << round(-1.4) << std::endl;
  std::cout << "round(1.6):\t" << round(1.6) << std::endl;
  std::cout << "round(-1.6):\t" << round(-1.6) << std::endl;
  return 0;
}

输出:

round(0.5):  1
round(-0.5): -1
round(1.4):  1
round(-1.4): -1
round(1.6):  2
round(-1.6): -2

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

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浮点标准不可能完美地表示为所有二进制数字表示的十进制数。

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