也许这似乎是一个有点罕见的问题,但我想找到一个能够将double
(c号)转换为long
(c号)的函数。没有必要保留双重信息。最重要的是:
double a,b;
long c,d;
c = f(a);
d = f(b);
这一定是事实:
所有(a < b)
和 适用于所有c < d
谢谢你们所有人。
答案 0 :(得分:5)
如果满足以下两个条件,您的要求是可行的:
sizeof(double)
定义为sizeof(long)
虽然第二个条件适用于每个广泛使用的平台,但第一个条件却没有。
如果您的平台上的两个条件都,那么您可以按如下方式实现该功能:
long f(double x)
{
if (x > 0)
return double_to_long(x);
if (x < 0)
return -double_to_long(-x);
return 0;
}
您有几种不同的方式来实现转换功能:
long double_to_long(double x)
{
long y;
memcpy(&y,&x,sizeof(x));
return y;
}
long double_to_long(double x)
{
long y;
y = *(long*)&x;
return y;
}
long double_to_long(double x)
{
union
{
double x;
long y;
}
u;
u.x = x;
return u.y;
}
请注意,建议不要使用第二个选项,因为它会中断strict-aliasing rule。
答案 1 :(得分:1)
从浮点到整数类型有四种基本转换:
floor - Rounds towards negative infinity, i.e. next lowest integer.
ceil[ing] - Rounds towards positive infinity, i.e. next highest integer.
trunc[ate] - Rounds towards zero, i.e. strips the floating-point portion and leaves the integer.
round - Rounds towards the nearest integer.
这些转换都不会给出您指定的行为,但floor
会允许稍微弱一点的条件(a < b) implies (c <= d)
。
如果double
值使用的空间比long
更多,那么由于存在原理,因此没有可以满足初始约束的映射。基本上,由于double
类型可以表示比long
类型更多的不同值,因此无法保留<
关系的严格部分顺序,因为多个double
类型long
类型}值将被强制映射到相同的{{1}}值。
另见:
答案 2 :(得分:1)
使用frexp()
让你大部分时间都在那里。它将数字拆分为指数和有效数(分数)。
假设long
的大小至少与double
相同,否则这是毫无意义的。 Pigeonhole principle
#include <math.h>
long f(double x) {
assert(sizeof(long) >= sizeof(double));
#define EXPOWIDTH 11
#define FRACWIDTH 52
int ipart;
double fraction = frexp(fabs(x), &ipart);
long lg = ipart;
lg += (1L << EXPOWIDTH)/2;
if (lg < 0) ipart = 0;
if (lg >= (1L << EXPOWIDTH)) lg = (1L << EXPOWIDTH) - 1;
lg <<= FRACWIDTH;
lg += (long) (fraction * (1L << FRACWIDTH));
if (x < 0) {
lg = -lg;
}
return lg;
}
-
注意:
EXPO的正确值取决于DBL_MAX_EXP
和DBL_MIN_EXP
以及double
类型的详细信息。
此解决方案在double
的极值附近映射相同的double
值。我稍后会看一下测试。
否则如上所述:覆盖两种类型。
由于long
通常是2补码而double
以符号幅度的方式排列,因此当double
为负数时需要额外的工作。还要注意-0.0。
long f(double x) {
assert(sizeof x == sizeof (long));
union {
double d;
long lg;
} u = { x*1.0 }; // *1.0 gets rid of -0.0
// If 2's complement - which is the common situation
if (u.lg < 0) {
u.lg = LONG_MAX - u.lg;
}
return u.lg;
}