替代 ceil() 和 floor() 以获得最接近的整数值,高于和低于浮点值?
Alternative to ceil() and floor() to get the closest integer values, above and below of a floating point value?
我正在寻找 C 中 ceil()
和 floor()
函数的替代方法,因为不允许我在项目中使用这些函数。
到目前为止,我构建的是一种棘手的来回方式,通过使用强制转换运算符以及从浮点值(在我的例子中是 double
)到 int
后来我需要最接近的整数,高于和低于给定的浮点值,也是 double
值,回到 double
:
#include <stdio.h>
int main(void) {
double original = 124.576;
double floorint;
double ceilint;
int f;
int c;
f = (int)original; //Truncation to closest floor integer value
c = f + 1;
floorint = (double)f;
ceilint = (double)c;
printf("Original Value: %lf, Floor Int: %lf , Ceil Int: %lf", original, floorint, ceilint);
}
输出:
Original Value: 124.576000, Floor Int: 124.000000 , Ceil Int: 125.000000
对于此示例,通常我不需要将 c
和 f
的 ceil 和 floor 整数值转换回 double
但我需要它们 double
在我的真实程序中。将其视为任务的要求。
虽然输出给出了所需的值并且到目前为止看起来是正确的,但我仍然担心这种方法是否真的那么正确和合适,或者更清楚地说,如果这种方法确实带来任何不良行为或发布到程序中或与其他替代方案相比给我带来性能损失,如果有任何其他可能的替代方案。
你知道更好的选择吗?如果是这样,为什么这个应该更好?
非常感谢。
你错过了一个重要的步骤:你需要检查数字是否已经是整数,所以对于 ceil
假设非负数(概括是微不足道的),使用类似
double ceil(double f){
if (f >= LLONG_MAX){
// f will be integral unless you have a really funky platform
return f;
} else {
long long i = f;
return 0.0 + i + (f != i); // to obviate potential long long overflow
}
}
这个谜题中的另一个缺失部分被我封闭的 if
覆盖了,它是检查 f
是否在 long long
的范围内。在通用平台上,如果 f
在 long long
的范围之外,那么无论如何它都是不可分割的。
请注意 floor
是微不足道的,因为 long long
的截断总是趋向于零。
Do you know a better alternative? And if so, why this one should be better?
OP'代码失败:
original
已经是整数了
original
和 -1.5
一样是负数。截断不是在那里。
original
刚好超出 int
范围。
original
不是数字。
另类构造
double my_ceil(double x)
当 x
超出整数范围时,使用转换为某些整数类型的技巧是一个问题。因此,首先检查 x
是否在足够宽的整数范围内(精度超过 double
的整数)。 x
之外的值已经是整数。建议选择最宽的整数 (u)intmax_t
。
请记住,转换为整数是向 0 的舍入,而不是 floor。如果 x
是 negative/positive 而代码是 ceil()
或 floor()
,则需要不同的处理。 OP 的代码遗漏了这一点。
我会避免 if (x >= INTMAX_MAX) {
,因为它涉及 (double) INTMAX_MAX
,其舍入和精确值为 "chosen in an implementation-defined manner"。相反,我会与 INTMAX_MAX_P1
进行比较。 some_integer_MAX
是一个 Mersenne Number 和 2 的补码,...MIN
是一个取反的 "power of 2".
#include <inttypes.h>
#define INTMAX_MAX_P1 ((INTMAX_MAX/2 + 1)*2.0)
double my_ceil(double x) {
if (x >= INTMAX_MAX_P1) {
return x;
}
if (x < INTMAX_MIN) {
return x;
}
intmax_t i = (intmax_t) x; // this rounds towards 0
if (i < 0 || x == i) return i; // negative x is already rounded up.
return i + 1.0;
}
由于 x
可能是 not-a-number,因此反转比较更有用,因为 NaN 的关系比较为假。
double my_ceil(double x) {
if (x >= INTMAX_MIN && x < INTMAX_MAX_P1) {
intmax_t i = (intmax_t) x; // this rounds towards 0
if (i < 0 || x == i) return i; // negative x is already rounded up.
return i + 1.0;
}
return x;
}
double my_floor(double x) {
if (x >= INTMAX_MIN && x < INTMAX_MAX_P1) {
intmax_t i = (intmax_t) x; // this rounds towards 0
if (i > 0 || x == i) return i; // positive x is already rounded down.
return i - 1.0;
}
return x;
}
我正在寻找 C 中 ceil()
和 floor()
函数的替代方法,因为不允许我在项目中使用这些函数。
到目前为止,我构建的是一种棘手的来回方式,通过使用强制转换运算符以及从浮点值(在我的例子中是 double
)到 int
后来我需要最接近的整数,高于和低于给定的浮点值,也是 double
值,回到 double
:
#include <stdio.h>
int main(void) {
double original = 124.576;
double floorint;
double ceilint;
int f;
int c;
f = (int)original; //Truncation to closest floor integer value
c = f + 1;
floorint = (double)f;
ceilint = (double)c;
printf("Original Value: %lf, Floor Int: %lf , Ceil Int: %lf", original, floorint, ceilint);
}
输出:
Original Value: 124.576000, Floor Int: 124.000000 , Ceil Int: 125.000000
对于此示例,通常我不需要将 c
和 f
的 ceil 和 floor 整数值转换回 double
但我需要它们 double
在我的真实程序中。将其视为任务的要求。
虽然输出给出了所需的值并且到目前为止看起来是正确的,但我仍然担心这种方法是否真的那么正确和合适,或者更清楚地说,如果这种方法确实带来任何不良行为或发布到程序中或与其他替代方案相比给我带来性能损失,如果有任何其他可能的替代方案。
你知道更好的选择吗?如果是这样,为什么这个应该更好?
非常感谢。
你错过了一个重要的步骤:你需要检查数字是否已经是整数,所以对于 ceil
假设非负数(概括是微不足道的),使用类似
double ceil(double f){
if (f >= LLONG_MAX){
// f will be integral unless you have a really funky platform
return f;
} else {
long long i = f;
return 0.0 + i + (f != i); // to obviate potential long long overflow
}
}
这个谜题中的另一个缺失部分被我封闭的 if
覆盖了,它是检查 f
是否在 long long
的范围内。在通用平台上,如果 f
在 long long
的范围之外,那么无论如何它都是不可分割的。
请注意 floor
是微不足道的,因为 long long
的截断总是趋向于零。
Do you know a better alternative? And if so, why this one should be better?
OP'代码失败:
original
已经是整数了original
和-1.5
一样是负数。截断不是在那里。original
刚好超出int
范围。original
不是数字。
另类构造
double my_ceil(double x)
当 x
超出整数范围时,使用转换为某些整数类型的技巧是一个问题。因此,首先检查 x
是否在足够宽的整数范围内(精度超过 double
的整数)。 x
之外的值已经是整数。建议选择最宽的整数 (u)intmax_t
。
请记住,转换为整数是向 0 的舍入,而不是 floor。如果 x
是 negative/positive 而代码是 ceil()
或 floor()
,则需要不同的处理。 OP 的代码遗漏了这一点。
我会避免 if (x >= INTMAX_MAX) {
,因为它涉及 (double) INTMAX_MAX
,其舍入和精确值为 "chosen in an implementation-defined manner"。相反,我会与 INTMAX_MAX_P1
进行比较。 some_integer_MAX
是一个 Mersenne Number 和 2 的补码,...MIN
是一个取反的 "power of 2".
#include <inttypes.h>
#define INTMAX_MAX_P1 ((INTMAX_MAX/2 + 1)*2.0)
double my_ceil(double x) {
if (x >= INTMAX_MAX_P1) {
return x;
}
if (x < INTMAX_MIN) {
return x;
}
intmax_t i = (intmax_t) x; // this rounds towards 0
if (i < 0 || x == i) return i; // negative x is already rounded up.
return i + 1.0;
}
由于 x
可能是 not-a-number,因此反转比较更有用,因为 NaN 的关系比较为假。
double my_ceil(double x) {
if (x >= INTMAX_MIN && x < INTMAX_MAX_P1) {
intmax_t i = (intmax_t) x; // this rounds towards 0
if (i < 0 || x == i) return i; // negative x is already rounded up.
return i + 1.0;
}
return x;
}
double my_floor(double x) {
if (x >= INTMAX_MIN && x < INTMAX_MAX_P1) {
intmax_t i = (intmax_t) x; // this rounds towards 0
if (i > 0 || x == i) return i; // positive x is already rounded down.
return i - 1.0;
}
return x;
}