以双精度返回错误代码



我想知道我是否可以在C:中以以下方式将错误代码返回为double

double getValue()
{
    double ret = 0;
    if (error1)
    {
        return -1;
    }
    if (error2)
    {
        return -2;
    }
    return ret = ....;
}
int main(void)
{
    double val = getValue();
    if (-1 == val)
    {
        printf("getValue: error1n")
        return -1;
    }
    else if (-2 == val)
    {
        printf("getValue: error2n");
        return -2;
    }
    ......
    return 0;
}

所以当返回值>=0时,它是可以用于计算的正确值。当值小于零时,出现错误。当我将返回值与-1或-2进行比较时,我会遇到浮点比较问题吗?

标志值是个坏主意。即使是双倍精度,浮点标志值也是双倍精度。

如果使用IEEE双精度浮点值,则值-1-2可以精确地表示为doubles,并且比较定义良好。如果您只复制double或只读取值,就不会出现"神奇的错误"。事实上,在具有传统2s补码32位ints的系统上,每个int都可以精确地表示为IEEE双精度浮点值。

现在,你认为像x /3. * 3.这样无关紧要的转换会破坏身份,所以代码是非常脆弱的:脆弱既是因为标志值是脆弱的,也是因为浮点等价在实践中往往是脆弱的。

在C++中,有无数种不那么脆弱的方法可以做到这一点。

enum error_code {a,b,c};
boost::variant<double, error_code> getValue();

是可以容纳doubleerror_code的标记并集。你可以看到一个std::expected提案,它是一个标记的并集,对第一个值是唯一有效的值有"偏见"(有点像std::experimental::optionalboost::variant之间的交叉)。

这两种情况都会导致以类型安全的方式返回值,其中错误是与非错误返回类型不同的类型值。

替代的解决方案包括单独返回错误代码(作为返回值,或者将指向错误代码的指针作为参数(我称之为ICU样式))。在这种情况下,double可以设置为一些无害的值(比如NaN),而不是保持未初始化状态。

double getValue( error_code* e );

error_code getValue( double* out );

其中CCD_ 15是错误代码的枚举。

@LightnessRacesinOrbit击败了我,但在输入后,我还是发布了它。

您可以通过将要设置的值作为指针参数并返回状态来完成此操作。这样,就不会禁止*ret的值。

int getValue(double *ret)
{
    *ret = ...;
    if (error1)
        return -1;
    if (error2)
        return -2;
    return 0;
}

然后调用代码可以是

double myval;
int err;
if ((err = getValue(&myval)) == 0)
    printf ("getValue() returned %fn", myval);
else
    printf ("getValue() returned error %dn", err);

是的,您可能会得到浮点错误。

因此,考虑使用异常,或者可能返回int错误代码,并在成功时填充double"out参数":

int getValue(double& ret)
{
    if (error1)
        return -1;
    if (error2)
        return -2;
    ret = ....;
    return 0;
}

这样做是不必要的,并且会使错误处理变得困难,您应该创建一个enum,在那里您可以根据需要添加或删除错误代码,而且您也不需要真正记住-1是什么或-2的意思,只需为每个错误提供一个描述性名称,并执行此

enum ErrorCodes {NoError, Error1, Error2, ... , ErrorN};
enum ErrorCodes getValue(double *value)
 {
    if (error1)
        return Error1;
    if (error2)
        return Error2;
    .
    .
    .
    if (errorN)
        return ErrorN;
    *value = resultOfCalculation;
    return NoError;
 }

然后

enum ErrorCode code;
double         value;
code = getValue(&value);
switch (code)
 {
    case NoError:
        /* use value here */
        break;
    case Error1:
        /* handle error 1 */
        break;
    /* and so on */
 }

我认为这是更好、更优雅的,因为您可以在任何时候应用它来进行稳健的错误检查,无论目标值是什么类型,这对structdoubleint阵列都是完全一样的。

最新更新