我知道C++为我们提供了一个ceil函数。出于练习的目的,我想知道如何在C ++中实现ceil函数。该方法的签名为public static int ceil(float num)。
请提供一些见解。
我想到了一个简单的方法:将num转换为字符串,找到小数点的索引,检查小数部分是否大于0。如果是,则返回num + 1,否则返回num。但我想避免使用字符串转换。
您可以将IEEE754浮点数的各个组成部分拆开,并自行实现逻辑:
#include <cstring>
float my_ceil(float f)
{
unsigned input;
memcpy(&input, &f, 4);
int exponent = ((input >> 23) & 255) - 127;
if (exponent < 0) return (f > 0);
// small numbers get rounded to 0 or 1, depending on their sign
int fractional_bits = 23 - exponent;
if (fractional_bits <= 0) return f;
// numbers without fractional bits are mapped to themselves
unsigned integral_mask = 0xffffffff << fractional_bits;
unsigned output = input & integral_mask;
// round the number down by masking out the fractional bits
memcpy(&f, &output, 4);
if (f > 0 && output != input) ++f;
// positive numbers need to be rounded up, not down
return f;
}
(在此插入通常的“不可移植”免责声明。)
frexp
和ldexp
来进行提取和重新组合。 - Oliver Charlesworthfrexp
返回一个浮点数,而不是整数。那么你打算如何屏蔽掉小数位呢? - fredoverflow这是一个针对正数的简单实现(该实现利用了将数字转换为(int)
时向零截断的特性):
int ceil(float num) {
int inum = (int)num;
if (num == (float)inum) {
return inum;
}
return inum + 1;
}
很容易将此扩展以处理负数。
您的问题要求返回int
类型的函数,但通常ceil()
函数返回与其参数相同的类型,因此范围没有问题(即float ceil(float num)
)。例如,如果num
为1e20,则上述函数会失败。
float
实现中无法准确表示,我怀疑这不是一种可靠的实现 ceil()
的方式。 - André Caroninum + 1
操作。 - Jarod42(+/-) M * 2^E
。指数E
告诉您距离二进制点有多远*。如果E
足够大,则没有小数部分,因此不需要进行任何操作。如果E
足够小,则没有整数部分,因此答案为1(假设M
非零且数字为正)。否则,E
告诉您二进制点出现在您的尾数中的位置,您可以使用它来进行检查,然后执行舍入。
* 不是十进制点,因为我们处于基于2而不是基于10的情况下。
frexp()
函数提取M
和E
。然后,您可以使用E
来确定M
中有多少位数字在二进制点上方,以及有多少位数字在下方。 - Oliver Charlesworth我的看法:
template <typename F>
inline auto ceil(F const f) noexcept
{
auto const t(std::trunc(f));
return t + (t < f);
}
trunc()
的话,就可以这样做。 - user1095108const int t = int(f);
。 - Volperf
可以是一个天文数字。 - user1095108之前的代码建议:
int ceil(float val)
{
int temp = val * 10;
if(val%10)
return (temp+1);
else
return temp;
}
无法编译:在第四行“if(val%10)”上收到“错误C2296:'%': 非法的左操作数类型为'float'”,因为不能在浮点数或双精度数上使用模运算符(%)。请参见:为什么我们不能在浮点数和双精度数类型操作数上使用运算符%? 此外,对于精度不大于1/10的十进制值,它也无法工作。
相比之下,先前的代码建议:
int ma_ceil(float num)
{ int a = num;
if ((float)a != num)
return num+1;
return num;
}
int ma_ceil(float num)
{ int a = num;
if ((float)a != num)
return a+1;
return a;
}
就像这样(纯粹从第一原理出发):
#include <iostream>
#include <type_traits>
template<typename T>
constexpr int truncate( const T val )
{
return static_cast<int>( val );
}
template<typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
constexpr T modulusFloat( const T divident,
const T divisor )
{
return divident - truncate( divident / divisor ) * divisor;
}
template<typename T>
constexpr T modulus( const T divident,
const T divisor ) noexcept
{
if constexpr ( std::is_floating_point_v<T> )
{
return modulusFloat( divident,
divisor );
}
else
{
return divident % divisor;
}
}
template<typename T>
constexpr T ceil( const T val ) noexcept
{
return val + (T)1 - modulus( val, (T)1 );
}
int main()
{
std::cout << ceil( 5.4 ) << '\n';
std::cout << ceil( -5.4 ) << '\n';
return 0;
}
类似这样:
double param, fractpart, intpart;
param = 3.14159265;
fractpart = modf (param , &intpart);
int intv = static_cast<int>(intpart); // can overflow - so handle that.
if (fractpart > some_epsilon)
++intv;
您只需要定义some_epsilon
值,使得在整数部分递增之前,小数部分比之前更大。其他需要考虑的因素包括符号(即值是否为负等)。
epsilon
的值为0。 - Oliver Charlesworthstd::numeric_limits<float>::epsilon()
的用途吗? - Violet Giraffe这是一个可以处理负数的代码:
int ceil(float num) {
int inum = (int)num;
if (num < 0 || num == (float)inum) {
return inum;
}
return inum + 1;
}
它也适用于负值
int ma_ceil(float num)
{ int a = num;
if ((float)a != num)
return num+1;
return num;
}
试试这个...
int ceil(float val)
{
int temp = val * 10;
if(val%10)
return (temp+1);
else
return temp;
}
val = 0.01
зЪДжГЕеЖµгАВ - Oliver Charlesworthceil
”问题的解决方案。 - R. Martinho Fernandes
std::ceil()
的签名不是public static int ceil(float)
。请注意,Java或C#的参考资料可能在快速浏览时看起来像C++。始终确保所咨询的参考资料是针对C++的。 - André Caron