Skip to content

Commit

Permalink
feat: Allow the generation of a random number on a normal distribution (
Browse files Browse the repository at this point in the history
#882)

* Added a feature to allow the generation of a random number on a normal distribution

Added two functions to number.h, which are overloads of each other. One will generate a number on a normal distribution given a mean and standard deviation, the other does the same but limits the output to a certain minimum and maximum value

Added the relevant unit tests to number_test.cpp

* Update number.h

* added requested changes
  • Loading branch information
pshukla441 authored Sep 4, 2024
1 parent ff9f8a7 commit eb3f29c
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
78 changes: 78 additions & 0 deletions include/faker-cxx/number.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,82 @@ F decimal(F max)
return decimal<F>(static_cast<F>(0.), max);
}

/**
* @brief Generates a number following a normal distribution given a mean and standard deviation.
*
* @tparam F the type of the generated number, must be a floating point type (float, double, long double).
*
* @param mean The mean value of the normal distribution
* @param standard_deviation the standard deviation of the normal distribution
*
* @throws std::invalid_argument if standard deviation is negative or infinity, or if mean is infinity
*
* @return F, a random floating point number following the specified normal distribution
*
* @code
* faker::number::normalDistribution(10, 3) // 12.374
* @encode
*/

template <std::floating_point F>
F normalDistribution(F mean, F standardDeviation)
{
if(standardDeviation < 0 || standardDeviation == INFINITY || mean == INFINITY)
{
throw std::invalid_argument("Standard Deviation cannot be negative");
}
else if(standardDeviation == 0)
{
return mean;
}

std::random_device randDev;
std::mt19937 PSRNG(randDev());

std::normal_distribution<F> dist(mean, standardDeviation);
return dist(PSRNG);
}

/**
* @brief Generates a number following a normal distribution within the specified range
*
* @tparam F the type of the generated number, must be a floating point type (float, double, long double).
*
* @param mean The mean value of the normal distribution
* @param standard_deviation The standard deviation of the normal distribution
* @param min The lowest possible output
* @param max The highest possible output
*
* @return F, a random floating point number following the specified normal distribution within the specified range
*
* @throws std::invalid_argument if min is greater than max
*
* @see normalDistribution<F>(F, F)
*
* @code
* faker::number::normalDistribution(10, 3, 9, 11) // 9
* @encode
*/

template <std::floating_point F>
F normalDistribution(F mean, F standardDeviation, F min, F max)
{
if (min > max)
{
throw std::invalid_argument("min cannot be larger than max");
}

F sample = normalDistribution(mean, standardDeviation);

if (sample > max)
{
sample = max;
}
else if(sample < min)
{
sample = min;
}
return sample;
}

}
46 changes: 46 additions & 0 deletions tests/modules/number_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,49 @@ TEST_F(NumberTest, givenRangeWithSameNumberSection_shouldGenerateThisNumberForDe

ASSERT_EQ(actualRandomNumber, 2.f);
}

//NormalDistribution(F, F) function tests

TEST_F(NumberTest, normalDistribution_givenInvalidStandardDeviation_shouldThrowInvalidArgument)
{
ASSERT_THROW(normalDistribution<float>(10.f, -0.01f), std::invalid_argument);
}

TEST_F(NumberTest, givenStandardDeviationOfINFINITY_shouldThrowInvalidArgument)
{
ASSERT_THROW(normalDistribution<float>(0.f, INFINITY), std::invalid_argument);
}

TEST_F(NumberTest, givenMeanOfINFINITY_shouldThrowInvalidArgument)
{
ASSERT_THROW(normalDistribution<float>(INFINITY, 3.f), std::invalid_argument);
}

TEST_F(NumberTest, givenStandardDeviationOf0_shouldGenerateMean)
{
const std::floating_point auto normalDistributionNumber = normalDistribution<float>(0.f, 0.f);

ASSERT_EQ(normalDistributionNumber, 0.f);
}

//NormalDistribution(F, F, F, F) tests

TEST_F(NumberTest, givenInvalidRangeArguments_shouldThrowInvalidArgument)
{
ASSERT_THROW(normalDistribution<float>(10.f, 3.f, 11.f, 10.f), std::invalid_argument);
}

TEST_F(NumberTest, givenValidRangeArguments_shouldGenerateDecimalInGivenRange)
{
const std::floating_point auto normalDistributionNumber = normalDistribution<float>(10.f, 1000.f, 9.9f, 11.1f);

ASSERT_TRUE(normalDistributionNumber <= 11.1f);
ASSERT_TRUE(normalDistributionNumber >= 9.9f);
}

TEST_F(NumberTest, givenRangeWithSameNumberSection_shouldGenerateTheExactNumber)
{
const std::floating_point auto normalDistributionNumber = normalDistribution<float>(10.f, 1000.f, 12.f, 12.f);

ASSERT_TRUE(normalDistributionNumber == 12.f);
}

0 comments on commit eb3f29c

Please sign in to comment.