Question

I still have not run it through enough tests however for some reason, using certain non-negative values, this function will sometimes pass back a negative value. I have done a lot of manual testing in calculator with different values but I have yet to have it display this same behavior.

I was wondering if someone would take a look at see if I am missing something.

float calcPop(int popRand1, int popRand2, int popRand3, float pERand, float pSRand)
{
    return ((((((23000 * popRand1) * popRand2) * pERand) * pSRand) * popRand3) / 8);
}

The variables are all contain randomly generated values:

popRand1: between 1 and 30

popRand2: between 10 and 30

popRand3: between 50 and 100

pSRand: between 1 and 1000

pERand: between 1.0f and 5500.0f which is then multiplied by 0.001f before being passed to the function above

Edit:

Alright so after following the execution a bit more closely it is not the fault of this function directly. It produces an infinitely positive float which then flips negative when I use this code later on:

pPMax = (int)pPStore;

pPStore is a float that holds popCalc's return.

So the question now is, how do I stop the formula from doing this? Testing even with very high values in Calculator has never displayed this behavior. Is there something in how the compiler processes the order of operations that is causing this or are my values simply just going too high?

Était-ce utile?

La solution

In this case it seems that when you are converting back to an int after the function returns it is possible that you reach the maximum value of an int, my suggestion is for you to use a type that can represent a greater range of values.

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

As you can see here, there are other types which have a bigger range. If these do not suffice I believe the latest boost version has just the thing for you.

Autres conseils

Throw an exception:

if (pPStore > static_cast<float>(INT_MAX)) {
    throw std::overflow_error("exceeds integer size");
} else {
   pPMax = static_cast<int>(pPStore);
}

or use float instead of int.

When you multiply the maximum values of each term together you get a value around 1.42312e+12 which is somewhat larger than a 32 bit integer can hold, so let's see what the standard has to say about floating point-to-integer conversions, in 4.9/1:

A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion trun- cates; that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented in the destination type.

So we learn that for a large segment of possible result values your function can generate, the conversion back to a 32 bit integer would be undefined, which includes making negative numbers.

You have a few options here. You could use a 64 bit integer type (long or long long possibly) to hold the value instead of truncating down to int.

Alternately you could scale down the results of your function by a factor of around 1000 or so, to keep the maximal results within the range of values that a 32 bit integer could hold.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top