将double映射为长数的函数

时间:2014-12-08 20:53:46

标签: c function double long-integer

也许这似乎是一个有点罕见的问题,但我想找到一个能够将double(c号)转换为long(c号)的函数。没有必要保留双重信息。最重要的是:

double a,b;

long c,d;

c = f(a);

d = f(b);

这一定是事实:

  所有 (a < b) 适用于所有 c < d

谢谢你们所有人。

3 个答案:

答案 0 :(得分:5)

如果满足以下两个条件,您的要求是可行的:

  1. 编译器将sizeof(double)定义为sizeof(long)
  2. 硬件使用IEEE 754 double-precision binary floating-point format
  3. 虽然第二个条件适用于每个广泛使用的平台,但第一个条件却没有。

    如果您的平台上的两个条件,那么您可以按如下方式实现该功能:

    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_EXPDBL_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;
}