Я до сих пор не провел его через достаточное количество тестов, однако по какой-то причине, используя определенные неотрицательные значения, эта функция иногда возвращает отрицательное значение. Я провел множество ручных тестов в калькуляторе с разными значениями, но мне пока не удалось отобразить это поведение.
Мне было интересно, если кто-нибудь взглянет на то, что я что-то упускаю.
float calcPop(int popRand1, int popRand2, int popRand3, float pERand, float pSRand)
{
return ((((((23000 * popRand1) * popRand2) * pERand) * pSRand) * popRand3) / 8);
}
Все переменные содержат случайно сгенерированные значения:
popRand1: от 1 до 30
popRand2: от 10 до 30
popRand3: от 50 до 100
pSRand: от 1 до 1000
pERand: между 1.0f и 5500.0f, который затем умножается на 0.001f перед передачей функции выше
Редактировать:
Хорошо, так что после того, как следите за выполнением немного более внимательно, это не ошибка этой функции напрямую. Он генерирует бесконечно положительное число с плавающей точкой, которое затем переворачивается отрицательно, когда я позже использую этот код:
pPMax = (int) pPStore;
pPStore — это число с плавающей точкой, которое содержит возврат popCalc.
Теперь возникает вопрос: как мне остановить формулу от этого? Тестирование даже с очень высокими значениями в Калькуляторе никогда не показывало такого поведения. Есть ли что-то в том, как компилятор обрабатывает порядок операций, который вызывает это, или мои значения просто слишком велики?
В этом случае кажется, что, когда вы возвращаете значение типа int после возврата функции, возможно, вы достигнете максимального значения типа int, я предлагаю вам использовать тип, который может представлять больший диапазон значений.
#include <iostream>
#include <limits>
#include <boost/multiprecision/cpp_int.hpp>
int main(int argc, char* argv[])
{
std::cout << "int min: " << std::numeric_limits<int>::min() << std::endl;
std::cout << "int max: " << std::numeric_limits<int>::max() << std::endl;
std::cout << "long min: " << std::numeric_limits<long>::min() << std::endl;
std::cout << "long max: " << std::numeric_limits<long>::max() << std::endl;
std::cout << "long long min: " << std::numeric_limits<long long>::min() << std::endl;
std::cout << "long long max: " << std::numeric_limits<long long>::max() << std::endl;
boost::multiprecision::cpp_int bigint = 113850000000;
int smallint = 113850000000;
std::cout << bigint << std::endl;
std::cout << smallint << std::endl;
std::cin.get();
return 0;
}
Как вы можете видеть здесь, есть другие типы, которые имеют больший диапазон. Если этого не достаточно, я считаю, что последняя версия Boost имеет только вещь для тебя.
Бросить исключение:
if (pPStore > static_cast<float>(INT_MAX)) {
throw std::overflow_error("exceeds integer size");
} else {
pPMax = static_cast<int>(pPStore);
}
или используйте float вместо int.
Когда вы умножаете максимальные значения каждого члена вместе, вы получаете значение около 1.42312e+12
который несколько больше, чем может содержать 32-битное целое число, поэтому давайте посмотрим, что стандарт должен сказать о преобразованиях с плавающей запятой в целое, в 4.9/1
:
Значение типа с плавающей запятой может быть преобразовано в значение типа
целочисленный тип. Конверсионные стволы; то есть дробная часть
отбрасывается Поведение не определено, если усеченное значение не может
быть представленным в типе назначения.
Итак, мы узнаем, что для большого сегмента возможных значений результата, который может сгенерировать ваша функция, преобразование обратно в 32-битное целое число будет неопределенным, что включает создание отрицательных чисел.
У вас есть несколько вариантов здесь. Вы можете использовать 64-битный целочисленный тип (long
или же long long
возможно) удерживать значение вместо усечения до int
,
В качестве альтернативы вы можете уменьшить результаты вашей функции примерно в 1000 раз, чтобы сохранить максимальные результаты в диапазоне значений, который может содержать 32-разрядное целое число.