cmath std :: pow функция, дающая неправильное значение при присвоении переменной?

Метод ниже отслеживает, сколько раз конкретные числа появляются из групп различных наборов чисел.

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).

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;
}
1

Другие решения

Пытаться

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