double转换long的疑问

  在lua(5.1.4)下面测试的时候使用0x100000000的时候出现了问题,打印结果很明显,如下所示:

Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print(0xffffffff)
4294967295
> print(0x100000000)
4294967295
> print(0x100000001)
4294967295

  一个同事给出了答复,但是说是强制转换的原因。不是太明白,按照long long转换成int的形式就是截断,就不会出现上面哪种都是4294967285的结果。5.1.4的源代码关于计算0xffffffff到整形的函数如下所示:

int luaO_str2d (const char *s, lua_Number *result) {
  char *endptr;
  *result = lua_str2number(s, &endptr);
  if (endptr == s) return 0;  /* conversion failed */
  if (*endptr == 'x' || *endptr == 'X')  /* maybe an hexadecimal constant? */
    *result = cast_num(strtoul(s, &endptr, 16));
  if (*endptr == '') return 1;  /* most common case */
  while (isspace(cast(unsigned char, *endptr))) endptr++;
  if (*endptr != '') return 0;  /* invalid trailing characters? */
  return 1;
}

  查看源代码可以知道cast_num就是转换成lua_number类型,也就是double类型。另外,直接写了一个简单的c++代码来看strtoul函数的结果,结果果真就是一样的,被截断了。代码如下(请跳过,放在这里自己记录一下):

void testStrtoul()
{
        double a;
        char pNum[] = "0x1100000000";
        a = strtoul(pNum, 0, 16);
        printf("%f, %f, %d
", a, sizeof(double));
        a += 1;
        unsigned long c = (unsigned long)pow(2,32) + 1;
        /*
         (1)pow is double
         (2)double --> unsigned long, the result is 0xffffffff
        */
        double cc = pow(2, 31) * 4.0;
        printf("cc = %f
", cc);
        c = cc;
        printf("%f, %u
", a, c);
}

  因此,想去搜索一下strtoul函数的实现,看到一篇帖子[1].发现返回值是unsigned long,也因此猜想是double转换long的时候出现的问题,直接使用上面的例子就可以看到结果。一开始也是怀疑double强制转换成long并且溢出的时候,结果都是0xffffffff,和这位仁兄想的是一样的[2]。
  但是,我非常不满意楼下给的回答:

(1)2楼给的上下界的溢出理论

(2)所谓的形象的比喻,水溢出杯子的理论

(3)double和long存储结构不一样

  唯一有点含金量的是第三个回答,给不明白的人指出一条路去思考。起码去重现看一下这方面的知识点,其他的就不多说了,因为文章中用的java,而自己使用的是c++,所以不同之处就大敢多说了。因为从上面的解释来说,如果从截断角度分析都不行,4294967296即使是double的存储结构也不会有那么多bit位占1的,再怎么截断也不能够出现)XFFFFFFFF的情况。

  对于自己碰到的问题,原因可以从下面这个帖子[4]看到:就是strtoul函数在溢出的时候就直接返回ULONG_MAX,而这个值也恰好就是(0xFFFFFFFF)

总结:

(1)对于自己的问题strtoul函数是自定义返回ULONG_MAX才会出现一直返回一个固定值的情况和[2]中的LZ遇到的情况很相近

(2)虽然说这些都是基本的计算机理论知识,但是还是要不断去探究其中的细节

(3)对于java的那种情况,是不是强制转换中作了什么处理不发表评论了,没有发言权

(4)c++中的double直接转换成long类型还是截断处理的,比如4294967296前置转化成long类型就是0,4294967295*2转换之后的结果为4294967294

参考:

[1]http://blog.csdn.net/czxyhll/article/details/7876084

[2]http://bbs.csdn.net/topics/330076483

[3]http://www.cnblogs.com/fly-height/articles/2340396.html

[4]http://www.cplusplus.com/reference/cstdlib/strtoul/

原文地址:https://www.cnblogs.com/pk-run/p/4013953.html