【问题标题】:cmath std::pow function giving wrong value when assigned to a variable?cmath std::pow 函数在分配给变量时给出错误的值?
【发布时间】:2014-01-12 10:46:23
【问题描述】:

下面的方法是跟踪特定数字从各种数字集合中出现的次数

void build_prob_distro(const std::vector<Foo>& num_sets, std::map<int, int>& prob_distro){
    int key;
    Foo cur_foo;

    for(unsigned int foo_num = 0; foo_num<num_sets.size(); foo_num++){
        cur_foo = num_sets.at(foo_num);
        key = 0;
        int val;
        for(int cur_foo_num=0; cur_foo_num<cur_foo.get_foo_length(); cur_foo_num++){
            std::cout << cur_foo.get_num_at(cur_foo_num)*std::pow(10, cur_foo.get_foo_length()-cur_foo_num-1) << std::endl;
            val = cur_foo.get_num_at(cur_foo_num)*std::pow(10, cur_foo.get_foo_length()-cur_foo_num-1);
            std::cout << val << std::endl;
            key = key + cur_foo.get_num_at(cur_foo_num)*std::pow(10, cur_foo.get_foo_length()-cur_foo_num-1);
        }

        prob_distro[key] += 1;
    }
}

我遇到的问题是,当我使用 std::pow() 方法计算我的地图的键值时,任何超过 100 的值都会被 -1 关闭(即 100 变为 99,103 变为 102,等等。 )。当我用 std::cout 打印出计算结果是正确的,但是一旦我将值分配给一个 int 变量,它就会得到 -1 错误。我一遍又一遍地查看代码,并没有立即发现任何问题。有关可能导致此问题的原因以及原因的任何建议?

我不认为 foo 类对这个示例/问题太重要,但我会发布它以防万一它实际上是某些问题的原因。

//Foo.h
#ifndef FOO_H
#define FOO_H

#include <string>
#include <vector>

class Foo
{
    public:
        Foo();
        Foo(const std::vector<int>& nums);
        int get_num_at(int pos) const;
        int get_foo_length() const;
        std::string to_string() const;
    private:
        std::vector<int> nums;

};

#endif // Foo_H


//Foo.cpp
#include "Foo.h"

#include <string>

Foo::Foo(const std::vector<int>& nums){
    for(int i=0; i<nums.size(); i++){
        this->nums.push_back(nums.at(i));
    }
}

Foo::Foo(){}


/*       SETTERS & GETTERS           */

int Foo::get_num_at(int pos) const{
    if(nums.size() != 0){
        return nums[pos];
    }

    return -1;
}

int Foo::get_foo_length() const{
    return nums.size();
}

/*       END SETTERS & GETTERS         */


std::string Foo::to_string() const{}

编辑:我知道有些人会立即指出在向量中使用比 Foo 类更容易的东西,但我还有其他功能需要与每个集合结合,所以这是我能想出的最好的方法来保持我的相关代码一起并允许它表示我感兴趣的任何长度整数值(即 foo 可以表示 1 就像它可以表示 10000 一样容易)。

【问题讨论】:

  • 您可能会遇到舍入错误。 pow() 会产生不精确的结果,double-to-int 转换会截断值,因此将 99.99999 转换为 int 会产生 99。我严重怀疑无论您在做什么,都需要使用浮点运算。
  • 我有一种预感,它与 pow 内部的 int/double 转换有关,但真正困扰我的是 std::cout
  • @MrJman006 输出默认四舍五入。在输出值之前添加&lt;&lt; std::setprecision(20) &lt;&lt; val,看看它是否仍然“正确”:)
  • @KeithThompson 您好 Keith,我只是在您发帖时发表评论,我同意这可能是四舍五入的问题,但为什么 std::cout 语句会正确显示?
  • @MrJman006 你的旅程开始了here

标签: c++ c++11 pow cmath


【解决方案1】:

您可能会遇到舍入错误,

所以,你可以试试std::lround

key += cur_foo.get_num_at(cur_foo_num) * std::lround(std::pow(10, cur_foo.get_foo_length() - cur_foo_num - 1));

或编写自己的pow_int 函数以避免使用float

constexpr int pow_int(int x, unsigned int n)
{
    // x ** (2n + 1) == ((x * x) ** n) * x
    // x ** 2n == (x * x) ** n
    // x ** 0 == 1
    return (((n >> 1) == 0) ? 1 : pow_int(x * x, n >> 1)) * (((n & 1) == 0) ? 1 : x);
}

或(线性版本)

int pow_int(int x, unsigned int n)
{
    int res = 1;

    for (unsigned int i = 0; i != n; ++i) {
        res *= x;
    }
    return res;
}

【讨论】:

  • 这实际上是我最终做的。我写了自己的 int 幂函数。我的与上一个实现非常相似。
【解决方案2】:

试试

key = key + cur_foo.get_num_at(cur_foo_num)*std::pow(10, cur_foo.get_foo_length()-cur_foo_num-1) + 0.5;

【讨论】:

  • 您可以使用std::lround(d) (c++11) 代替int(d + 0.5) 技巧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-27
  • 1970-01-01
  • 2015-11-19
  • 1970-01-01
  • 2017-09-28
  • 1970-01-01
相关资源
最近更新 更多