【问题标题】:C++ - g++ casting int to double gives negative valueC++ - g++ 将 int 转换为 double 给出负值
【发布时间】:2012-03-10 11:43:24
【问题描述】:

正在使用 mingw 在 windows 上进行项目:

C:\Users\...>g++ -dumpversion
4.5.0

当我在 g++ v 4.2.4 下编译代码时,我遇到了分段错误 - 几个小时后,我将其固定到该行:

double decimal = ((double) rand()) / (RAND_MAX + 1);

由于某种原因,这给出了负值(一件事导致另一件事)。 什么原因?

编辑:cpp:

#include <iostream>
#include "Random.h"
#include <math.h>

using namespace std;
double Random::exponential(int T) {
    double decimal = ((double) rand()) / (RAND_MAX + 1);
    //  std::cout << "decimal : " << decimal << std::endl;
    return log(1 - decimal)*(-T);
}
//etc

h:

#ifndef RANDOM_H
#define RANDOM_H

#include <cstdlib>
#include <math.h>
class Random {
public:
    static double exponential(int T);
    static int random_int(int min, int max);
    static bool coin(); //50% true 50% false
};

#endif  /* RANDOM_H */

刚刚注意到(math.h)的双重包含,但这应该不是问题

【问题讨论】:

  • 这不应该正常发生。 rand() 的声明方式可能存在一些问题。
  • 不要在 C++ 中使用不安全的 C 风格转换(永远)。尝试使用 static_cast 或其他东西,看看效果如何。
  • @John - 你能详细说明一下吗?
  • 不要在 C++ 中这样做:(double) rand()。相反,请执行static_cast&lt;double&gt;(rand()) 之类的操作。原因是 C 风格的强制转换是不安全的,它对编译器说“我不在乎这个表达式看起来多么愚蠢,只要按照我说的方式将这些部分混合在一起即可。” C++ 风格转换做一些更具体的事情,如果表达式没有意义(例如 static_casting a pointer into a double or something)会给出错误。
  • @JohnZwinck C 风格的转换在转换数字类型时是非常安全的,因为它们无论如何都会变成static_casts

标签: c++ casting int double


【解决方案1】:

在您的情况下,RAND_MAX 是存储它的整数类型的最大值,因此RAND_MAX + 1 为您提供最大负值。从技术上讲,这是有符号整数溢出,这是未定义的行为,因此任何事情都可能发生。

正如 J-16 指出的那样,您需要这样做,

double decimal = (double)rand() / ((double)RAND_MAX + 1);

【讨论】:

  • (double)RAND_MAX + 1,如果你想拥有[0,1)
  • 好吧 - 只是一个细节 - 我很明确 - 使用 () - 将 rand() 部分转换为双倍。它在 4.5.5 的 10^5 次运行中从未出现过一次故障,并且在 4.2.4 中立即出现故障。怎么会?
  • @Mr_and_Mrs_D 因为你将它除以一个负值(因为RAND_MAX 被定义为整数类型可以容纳的最大值,当你给它加1时,它变成了最大负数value) 导致负值
  • 要确定为什么它在一个编译器而不是另一个版本中失败,您可能需要检查生成的代码。此外,请确保您在每个上使用相同的编译器选项。
  • @JohnZwinck 你不必去检查生成的代码,这是一个简单的未定义行为的例子,导致除以负数
【解决方案2】:

在您的环境中,RAND_MAX 可能设置为最大的正数,例如 0x7fff (32767)。当您向其中添加一个时,它实际上会环绕到最小的负数,例如 0x8000 (-32768)。当然,这一切都假设二进制补码,并且数字将自动换行,这两者都不是标准规定的)。

因此,因为您将 rand 中的正或零值除以负值,所以大多数时候您会得到一个负数,偶尔会为零。

您可以在除法中使用RAND_MAX 而不是RAND_MAX+1。这将避免给你一个负数,但你会遇到另一个问题。

因为rand 有可能返回RAND_MAX,所以除法的结果可能为1。当您尝试计算log (1 - decimal) * (-T) 时,取对数为零,您最终会得到一个错误:log(0) 没有在数学中定义。

我建议通过使用类似这样的方法来避免这个问题:

double Random::exponential (int T) {
    int randVal = rand();
    while (randVal == RAND_MAX)
        randVal = rand();

    double decimal = (double) randVal / RAND_MAX;
    return log (1 - decimal) * (-T);
}

这将避免极端情况,但代价是偶尔会重复调用 rand

【讨论】:

    猜你喜欢
    • 2014-07-13
    • 1970-01-01
    • 2012-06-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多