Precision to drand48 - c++

How can I add precision to drand48() in C++?
I am using it in a function like:
double x = drand48()%1000+1;
to generate numbers below 1000.
But then I get this error:
error: invalid operands of types ‘double’ and ‘int’ to binary ‘operator%’
This does not happen when I use:
double x = rand()%1000+1;
Why and what is the difference between rand() and drand48()?

drand48 returns a number from the interval [0.0, 1.0). Are you looking for a number between 1 and 1000? In this case, you need to multiply by 999 and add 1.
Actually, what are you expecting?

drand48() returns a double, whereas rand() returns int.
Furthermore, drand48() returns a value that's distributed between [0.0, 1.0), so your formula needs to change:
double x = drand48() * 1000.0 + 1; // floating-point values from [1, 1001)
or
double x = (int)(drand48() * 1000.0) + 1; // integer values from [1, 1000]
You could either scale the result of drand48() as above, or use lrand48() with your existing formula.

drand48 returns a double in the range of 0.0 to 1.0. You want to multiply that by the range you're looking to generate. double x = drand48() * 1000.0

Related

3D vector angle calculation formula returns nan (acos argument bigger than 1 somehow... )

Because of test1 and test2 i know that the issue here is that the argument of acos is larger than 1 and thus i get nAn as result. But what exactly is wrong with my calculation?
Vectors are:
v1(3,4,0),
v2(0,1,0)
Expected result for the angle is 36.87°
double Vector::angle(const Vector& input) const
{
double test1 = sqrt(this->length() * input.length()); //equals 2.23607
double test2 = this->dotProd(input); //equals 4
double result = acos(this->dotProd(input) / sqrt(this->length() * input.length()));
return result;
}
But what exactly is wrong with my calculation?
The sqrt at the denominator here:
double result = acos(this->dotProd(input) / sqrt(this->length() * input.length()));
It should be:
double result = std::acos(this->dotProd(input) / (this->length() * input.length()));
You could also infer that from dimentional analysis. If you assume the vector
represents, say, the displacement between two points in meters (m):
The vector length has unit [m];
The dot product has unit [m * m];
So you pass acos a parameter whose dimension is [m], while it should be
dimensionless.

A small number is rounded to zero

I have the following values:
i->fitness = 160
sum_fitness = 826135
I do the operation:
i->roulette = (int)(((i->fitness / sum_fitness)*100000) + 0.5);
But i keep getting 0 in i->roulette.
I also tried to save i->fitness / sum_fitness in a double variable and only then applying the other operations, but also this gets a 0.
I'm thinking that's because 160/826135 is such a small number, then it rounds it down to 0.
How can i overcome this?
Thank you
edit:
Thanks everyone, i eventually did this:
double temp = (double)(i->fitness);
i->roulette = (int)(((temp / sum_fitness)*100000) + 0.5);
And it worked.
All the answers are similar so it's hard to choose one.
You line
i->roulette = (int)(((i->fitness / sum_fitness)*100000) + 0.5);
is casting the value to int which is why any float operation is truncated
try
i->roulette = (((i->fitness / sum_fitness)*100000) + 0.5);
and make sure that either 'sum_fitness' or 'i->fitness' is of of a float or double type to make the division a floating point division -- if they are not you will need to cast one of them before dividing, like this
i->roulette = (((i->fitness / (double)sum_fitness)*100000) + 0.5);
If you want to make this as a integer calculation you could also try to change the order of the division and multiplication, like
i->roulette = ( i->fitness *100000) / sum_fitness;
which would work as long as you don't get any integer overflow, which in your case would occur only if fitness risk to be above 2000000.
I'm thinking that's because 160/826135 is such a small number, then it rounds it down to 0.
It is integer division, and it is truncated to the integral part. So yes, it is 0, but there is no rounding. 99/100 would also be 0.
You could fix it like by casting the numerator or the denominator to double:
i->roulette = ((i->fitness / static_cast<double>(sum_fitness))*100000) + 0.5;

Code for normal distribution returns unexpected values [duplicate]

From this question: Random number generator which gravitates numbers to any given number in range? I did some research since I've come across such a random number generator before. All I remember was the name "Mueller", so I guess I found it, here:
Box-Mueller transform
I can find numerous implementations of it in other languages, but I can't seem to implement it correctly in C#.
This page, for instance, The Box-Muller Method for Generating Gaussian Random Numbers says that the code should look like this (this is not C#):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
double gaussian(void)
{
static double v, fac;
static int phase = 0;
double S, Z, U1, U2, u;
if (phase)
Z = v * fac;
else
{
do
{
U1 = (double)rand() / RAND_MAX;
U2 = (double)rand() / RAND_MAX;
u = 2. * U1 - 1.;
v = 2. * U2 - 1.;
S = u * u + v * v;
} while (S >= 1);
fac = sqrt (-2. * log(S) / S);
Z = u * fac;
}
phase = 1 - phase;
return Z;
}
Now, here's my implementation of the above in C#. Note that the transform produces 2 numbers, hence the trick with the "phase" above. I simply discard the second value and return the first.
public static double NextGaussianDouble(this Random r)
{
double u, v, S;
do
{
u = 2.0 * r.NextDouble() - 1.0;
v = 2.0 * r.NextDouble() - 1.0;
S = u * u + v * v;
}
while (S >= 1.0);
double fac = Math.Sqrt(-2.0 * Math.Log(S) / S);
return u * fac;
}
My question is with the following specific scenario, where my code doesn't return a value in the range of 0-1, and I can't understand how the original code can either.
u = 0.5, v = 0.1
S becomes 0.5*0.5 + 0.1*0.1 = 0.26
fac becomes ~3.22
the return value is thus ~0.5 * 3.22 or ~1.6
That's not within 0 .. 1.
What am I doing wrong/not understanding?
If I modify my code so that instead of multiplying fac with u, I multiply by S, I get a value that ranges from 0 to 1, but it has the wrong distribution (seems to have a maximum distribution around 0.7-0.8 and then tapers off in both directions.)
Your code is fine. Your mistake is thinking that it should return values exclusively within [0, 1]. The (standard) normal distribution is a distribution with nonzero weight on the entire real line. That is, values outside of [0, 1] are possible. In fact, values within [-1, 0] are just as likely as values within [0, 1], and moreover, the complement of [0, 1] has about 66% of the weight of the normal distribution. Therefore, 66% of the time we expect a value outside of [0, 1].
Also, I think this is not the Box-Mueller transform, but is actually the Marsaglia polar method.
I am no mathematician, or statistician, but if I think about this I would not expect a Gaussian distribution to return numbers in an exact range. Given your implementation the mean is 0 and the standard deviation is 1 so I would expect values distributed on the bell curve with 0 at the center and then reducing as the numbers deviate from 0 on either side. So the sequence would definitely cover both +/- numbers.
Then since it is statistical, why would it be hard limited to -1..1 just because the std.dev is 1? There can statistically be some play on either side and still fulfill the statistical requirement.
The uniform random variate is indeed within 0..1, but the gaussian random variate (which is what Box-Muller algorithm generates) can be anywhere on the real line. See wiki/NormalDistribution for details.
I think the function returns polar coordinates. So you need both values to get correct results.
Also, Gaussian distribution is not between 0 .. 1. It can easily end up as 1000, but probability of such occurrence is extremely low.
This is a monte carlo method so you can't clamp the result, but what you can do is ignore samples.
// return random value in the range [0,1].
double gaussian_random()
{
double sigma = 1.0/8.0; // or whatever works.
while ( 1 ) {
double z = gaussian() * sigma + 0.5;
if (z >= 0.0 && z <= 1.0)
return z;
}
}

arbitrary datatype ratio converter

I have following code:
template<typename I,typename O> O convertRatio(I input,
I inpMinLevel = std::numeric_limits<I>::min(),
I inpMaxLevel = std::numeric_limits<I>::max(),
O outMinLevel = std::numeric_limits<O>::min(),
O outMaxLevel = std::numeric_limits<O>::max() )
{
double inpRange = abs(double(inpMaxLevel - inpMinLevel));
double outRange = abs(double(outMaxLevel - outMinLevel));
double level = double(input)/inpRange;
return O(outRange*level);
}
the usage is something like this:
int value = convertRatio<float,int,-1.0f,1.0f>(0.5);
//value is around 1073741823 ( a quarter range of signed int)
the problem is for I=int and O=float with function default parameter:
float value = convertRatio<int,float>(123456);
the line double(inpMaxLevel - inpMinLevel) result is -1.0, and I expect it to be 4294967295 in float.
do you have any idea to do it better?
the base idea is just to convert a value from a range to another range with posibility of different data type.
Adding to romkyns answer, besides casting all values to doubles before casting to prevent overflows, your code returns wrong results when the lower bounds are distinct than 0, because you don't adjust the values appropiately. The idea is mapping the range [in_min, in_max] to the range [out_min, out_max], so:
f(in_min) = out_min
f(in_max) = out_max
Let x be the value to map. The algorithm is something like:
Map the range [in_min, in_max] to [0, in_max - in_min]. To do this, substract in_min from x.
Map the range [0, in_max - in_min] to [0, 1]. To do this, divide x by (in_max - in_min).
Map the range [0, 1] to [0, out_max - out_min]. To do this, multiply x by (out_max - out_min).
Map the range [0, out_max - out_min] to [out_min, out_max]. To do this, add out_min to x.
The following implementation in C++ does this (I will forget the default values to make the code clearer:
template <class I, class O>
O convertRatio(I x, I in_min, I in_max, O out_min, O out_max) {
const double t = ((double)x - (double)in_min) /
((double)in_max - (double)in_min);
const double res = t * ((double)out_max - (double)out_min) + out_min;
return O(res);
}
Notice that I didn't took the absolute value of the range sizes. This allows reverse mapping. For example, it makes possible to map [-1.0, 1.0] to [3.0, 2.0], giving the following results:
convertRatio(-1.0, -1.0, 1.0, 3.0, 2.0) = 3.0
convertRatio(-0.8, -1.0, 1.0, 3.0, 2.0) = 2.9
convertRatio(0.8, -1.0, 1.0, 3.0, 2.0) = 2.1
convertRatio(1.0, -1.0, 1.0, 3.0, 2.0) = 2.0
The only condition needed is that in_min != in_max (to prevent division by zero) and out_min != out_max (otherwise, all inputs will be mapped to the same point). To prevent rounding errors, try to not use small ranges.
Try
(double) inpMaxLevel - (double) inpMinLevel
instead. What you are doing currently is subtracting max from min while the numbers are still of type int - which necessarily overflows; a signed int is fundamentally incapable of representing the difference between its min and max.

Percentage calculation around 0.5 (0.4 = -20% and 0.6 = +20%)

I'm in a strange situation where I have a value of 0.5 and I want to convert the values from 0.5 to 1 to be a percentage and from 0.5 to 0 to be a negative percentage.
As it says in the title 0.4 should be -20%, 0.3 should be -40% and 0.1 should be -80%.
I'm sure this is a simple problem, but my mind is just refusing to figure it out :)
Can anyone help? :)
What we want to do is to scale the range (0; 1) to (-100; 100):
percentage = (value - 0.5) * 200;
The subtraction transforms the value so that it's in the range (-0.5; 0.5), and the multiplication scales it to the range of (-100; 100).
percent = ((value - 0.5) / 0.5) * 100
This will generate from -100 to 100. You want to subtract your zero value (0.5) from the given value, and divide by the range that should give 100% (also 0.5 in your example). Then multiply by 100 to convert to percentage.
Normalize it, and you're done:
// Assuming x is in the range (0,1)
x *= 2.0; // x is in the range (0,2)
x -= 1.0; // (-1,1)
x *= 100; // (-100,100)