简体   繁体   English

C++中是否有截断function?

[英]Is there a trunc function in C++?

I searched around and couldn't find the trunc function for C++.我四处搜索,找不到 C++ 的trunc function。 I know I can do this:我知道我可以这样做:

int main()
{
    double a = 12.566789;
    cout << setprecision(2) << fixed << (int)(a * 100) / 100.0 << endl;
    return 0;
}

but I'm not sure it's the best way to do this.但我不确定这是最好的方法。 Thank you.谢谢你。

If your C library is so old that it lacks a trunc function (specified in C99), you can easily implement one based on floor and ceil (specified in C89)如果您的 C 库太旧以至于缺少trunc function(在 C99 中指定),您可以轻松地实现基于floorceil (在 C89 中指定)的库

double trunc(double d){ return (d>0) ? floor(d) : ceil(d) ; }

trunc is there, in <cmath> : trunc在那里,在<cmath>

#include <iostream>
#include <cmath>

int main() {
        std::cout << trunc(3.141516) << std::endl; 
}

I suppose you're looking for something else?我想你在寻找别的东西?

There's a trunc function in C that you can use in C++ C 中有一个截断 function 可以在 C++ 中使用

trunc(a*100)/100

Keep in mind that you still have to specify formatting requests, because floating point can't represent all real numbers exactly, and you could get output like 12.5600000001 or 12.55999999 if you don't tell the output code the precision you want.请记住,您仍然必须指定格式化请求,因为浮点数不能准确地表示所有实数,如果您不告诉 Z78E6221F6393D1356681DB398F14CE6D 代码您想要的精度,您可以获得像12.560000000112.55999999这样的 output。

TL;DR TL;博士

Use the following for output:对 output 使用以下内容:

cout << setprecision(2) << fixed << a<< endl;

And the following if you need a truncated result somewhere during a mathematical calculation:如果在数学计算过程中某处需要截断结果,请执行以下操作:

trunc(a*100)/100

(Or better yet, use fixed-point math.) (或者更好的是,使用定点数学。)

Sure.当然。 Use the trunc() function from math.h.使用 math.h 中的trunc() function。 It's a C function, but it works as well in C++ as it does in C.这是一个 C function,但它在 C++ 中的效果与在 Z0D61F8370CAD14DE421 中一样好。 If you want to keep a couple digits, you can always:如果您想保留几个数字,您可以随时:

double a = 12.566789;
double b = trunc(a * 100) / 100.0;

If you're using an ancient C or C++ library that doesn't implement trunc , use boost::math::trunc .如果您使用的是未实现trunc的古老 C 或 C++ 库,请使用boost::math::trunc

I've developed a very fast trunc-function:我开发了一个非常快速的截断函数:

double ftrunc( double d )
{
    static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) not equal to sizeof(uint64_t)");
    static_assert(numeric_limits<double>::is_iec559,  "double must be IEEE-754");
    // assume size_t is our CPU's native register-width
    static_assert(sizeof(size_t) == sizeof(uint64_t) || sizeof(size_t) == sizeof(uint32_t), "register-width must be 32 or 64 bit");
    if constexpr( sizeof(size_t) == sizeof(uint64_t) )
    // we have 64 bit registers
    {
        unsigned const MANTISSA_BITS           = 52,
                       EXP_BIAS                = 0x3FF,
                       INF_NAN_BASE            = 0x7FF;
        uint64_t const EXP_MASK                = (uint64_t)0x7FF                      << MANTISSA_BITS,
                       SIGN_MASK               = (uint64_t)0x800                      << MANTISSA_BITS ,
                       MIN_INTEGRAL_DIGITS_EXP = (uint64_t) EXP_BIAS                  << MANTISSA_BITS,
                       MIN_INTEGRAL_ONLY_EXP   = (uint64_t)(EXP_BIAS + MANTISSA_BITS) << MANTISSA_BITS,
                       INF_NAN_EXP             = (uint64_t)INF_NAN_BASE               << MANTISSA_BITS,
                       NEG_MANTISSA_MASK       = 0x000FFFFFFFFFFFFFu;
        union
        {
            double   du;
            uint64_t dx;
        };
        du = d;
        uint64_t exp = dx & EXP_MASK;
        if( exp >= MIN_INTEGRAL_DIGITS_EXP )
            // value has integral digits
            if( exp < MIN_INTEGRAL_ONLY_EXP )
            {
                // there are fraction-digits to mask out, mask them
                unsigned shift  = (unsigned)(exp >> MANTISSA_BITS) - EXP_BIAS;
                dx             &= ~(NEG_MANTISSA_MASK >> shift);
                return du;
            }
            else
                if( exp < INF_NAN_EXP )
                    // value is integral
                    return du;
                else
                    // infinite, NaN, SNaN
                    // raise exception on SNaN if necessary
                    return du + du;
        else
        {
            // below  +/-1.0
            // return +/-0.0
            dx &= SIGN_MASK;
            return du;
        }
    }
    else if constexpr( sizeof(size_t) == sizeof(uint32_t) )
    // we have 32 bit registers
    {
        unsigned const MANTISSA_BITS           = 52,
                       HI_MANTISSA_BITS        = 20,
                       EXP_BIAS                = 0x3FF,
                       INF_NAN_BASE            = 0x7FF;
        uint32_t const EXP_MASK                = (uint32_t)0x7FFu                        << HI_MANTISSA_BITS,
                       SIGN_MASK               = (uint32_t)0x800u                        << HI_MANTISSA_BITS,
                       MIN_INTEGRAL_DIGITS_EXP = (uint32_t) EXP_BIAS                     << HI_MANTISSA_BITS,
                       MAX_INTEGRAL32_EXP      = (uint32_t)(EXP_BIAS + HI_MANTISSA_BITS) << HI_MANTISSA_BITS,
                       MIN_INTEGRAL_ONLY_EXP   = (uint32_t)(EXP_BIAS + MANTISSA_BITS)    << HI_MANTISSA_BITS,
                       INF_NAN_EXP             = (uint32_t)INF_NAN_BASE                  << HI_MANTISSA_BITS,
                       NEG_HI_MANTISSA_MASK    = 0x000FFFFFu,
                       NEG_LO_MANTISSA_MASK    = 0xFFFFFFFFu;
        union
        {
            double du;
            struct
            {
                uint32_t dxLo;
                uint32_t dxHi;
            };
        };
        du = d;
        uint32_t exp = dxHi & EXP_MASK;
        if( exp >= MIN_INTEGRAL_DIGITS_EXP )
            // value has integral digits
            if( exp < MIN_INTEGRAL_ONLY_EXP )
                // there are fraction-digits to mask out
                if( exp <= MAX_INTEGRAL32_EXP )
                {
                    // the fraction digits are in the upper dword, mask them and zero the lower dword
                    unsigned shift  = (unsigned)(exp >> HI_MANTISSA_BITS) - EXP_BIAS;
                    dxHi           &= ~(NEG_HI_MANTISSA_MASK >> shift);
                    dxLo            = 0;
                    return du;
                }
                else
                {
                    // the fraction digits are in the lower dword, mask them
                    unsigned shift  = (unsigned)(exp >> HI_MANTISSA_BITS) - EXP_BIAS - HI_MANTISSA_BITS;
                    dxLo           &= ~(NEG_LO_MANTISSA_MASK >> shift);
                    return du;
                }
            else
                if( exp < INF_NAN_EXP )
                    // value is integral
                    return du;
                else
                    // infinite, NaN, SNaN
                    // raise exception on SNaN if necessary
                    return du + du;
        else
        {
            // below  +/-1.0
            // return +/-0.0
            dxHi &= SIGN_MASK;
            dxLo  = 0;
            return du;
        }
    }
}

It's faster than most implemementations.它比大多数实现都快。 On my Ryzen 7 1800X the average execution-time of values >= 2^0 and <= 2^54 is 12 clock cycles.在我的 Ryzen 7 1800X 上,值 >= 2^0 和 <= 2^54 的平均执行时间是 12 个时钟周期。

use ceil or floor from cmath使用 cmath 的ceilfloor

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM