数值乘以 -1 的数学不好?

Bad Math with value multiplied by -1?

给定以下基本代码:

double x = 3;
return x *-1;

我希望 return 给出 -3 作为结果。但是,我得到的实际值约为 1.844674e+19(受输出限制)或一个疯狂的大数字。简单地做 return -x; 也行不通。

这样更改代码:

double x = 3;
return x *-1.0;

Returns 正确的输出。 这似乎是一些整数与双精度或布尔值的问题。 我知道在不明确将其设为双精度数的情况下对整数进行除法可以得到 0 而不是分数,但我从未见过它会导致乘法或加法问题。

有人可以告诉我发生了什么,或者指出对行为的解释以及如何处理吗?

编辑:这是我机器上的一个可验证示例。

函数:

// [[Rcpp::export]]
double test1(double data)
{
  std::vector<double> testArray(data);
  return (testArray.size()*-1);
}

来自 R 运行 与:

test1(4)

结果:

[1] 1.844674e+19

我能够将问题缩小到向量的大小。因此,对于任何正整数大小,.size() 函数乘以 -1 都会得到疯狂的值。乘以 -1.0 效果非常好。

编辑 2:我想我明白了。 Toby 是对的,它是一个未转换为 double 的无符号值。 在我的原始样本中:

// [[Rcpp::export]]
double test1(double data)
{
  std::vector<double> testArray(data);
  double arraySize = testArray.size();
  return (arraySize*-1);
}

首先将其转换为双精度数并乘以 -1.0,效果非常好。

尽管您认为您的代码与此类似:

#include <iostream>

double f()
{
    double x = 3;
    return x * -1;
}

int main()
{
    std::cout << f() << std::endl;
}

您的代码实际上从向量的 size() 的结果中获取 x 的类型 - 这个 returns a std::size_t:

#include <cstdint>
#include <iostream>

double f()
{
    std::size_t x = 3;
    return x * -1;
}

int main()
{
    std::cout << f() << std::endl;
}

这里发生的是 std::size_t 乘以 int。一个参数有符号和一个无符号时的提升规则说(来源:CppReference

if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned operand's type.

std::size_t 通常比 int 排名更高,所以我们现在将 3 乘以 (std::size_t)-1 - 一个很大的数字。然后当我们return时,这个大数被转换为double来匹配f()的签名。

可以通过以下几种方式避免此问题:

  • size()的结果存储到一个有符号或浮点类型的变量中,并用它来乘法。
  • 乘法时将size()使用static_cast<>的结果转换为有符号或浮点类型。
  • 乘以浮点常数(例如 -1.0)- 这将导致另一个参数被提升为浮点数。