How can i generate float random values in C? (also negative)
In general to generate random numbers from an arbitrary distribution you'd first generate uniform random numbers and then pass them to the inverse of the cumulative distribution function.
Assume for example that you want random numbers with uniform distribution on the interval [-10.0, 10.0] and all you've got is random numbers from [0.0, 1.0]. Cumulative distribution function of the uniform distribution on [-10.0, 10.0] is:
cdf(x) = 0.05 * x + 0.5 for x in [-10.0, 10.0]
This expresses the probability that a random number generated is smaller than x. The inverse is
icdf(y) = 20.0 * y - 10.0 for y in [0.0, 1.0]
(You can obtain this easily on paper by switching the x and y axis).
Hence to obtain random numbers uniformly distributed on [-10.0, 10.0] you can use the following code:
#include <stdlib.h>
// Returns uniformly distributed random numbers from [0.0, 1.0].
double uniform0to1Random() {
double r = random();
return r / ((double)RAND_MAX + 1);
}
// Returns uniformly distributed random numbers from [-10.0, 10.0].
double myRandom() {
return 20.0 * uniform0to1Random() - 10.0;
}
In fact, you don't need uniform0to1Random() since there are already a lot of good uniform random numbers generators from [0.0, 1.0] (e.g. in the boost library).
You can use the method to generate random numbers with nearly any probability distribution you want by sampling the inverse cumulative distribution as shown above.
See http://en.wikipedia.org/wiki/Inverse_transform_sampling for more details.
Following will give you a float in range between -max/2 up to +max/2:
float max = 5000;
float r = max * ((float)rand()/(float)RAND_MAX - 0.5);
Edit Since the question was edited for C only:
This page is pretty helpful: http://www.geekpedia.com/tutorial39_Random-Number-Generation.html
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
//use this first function to seed the random number generator,
//call this before any of the other functions
void initrand()
{
srand((unsigned)(time(0)));
}
//generates a psuedo-random float between 0.0 and 0.999...
float randfloat()
{
return rand()/(float(RAND_MAX)+1);
}
//generates a psuedo-random float between 0.0 and max
float randfloat(float max)
{
return randfloat()*max;
}
//generates a psuedo-random float between min and max
float randfloat(float min, float max)
{
if (min>max)
return randfloat()*(min-max)+max;
else
return randfloat()*(max-min)+min;
}
//generates a psuedo-random double between 0.0 and 0.999...
double randdouble()
{
return rand()/(double(RAND_MAX)+1);
}
//generates a psuedo-random double between 0.0 and max
double randdouble(double max)
{
return randdouble()*max;
}
//generates a psuedo-random double between min and max
double randdouble(double min, double max)
{
if (min>max)
return randdouble()*(min-max)+max;
else
return randdouble()*(max-min)+min;
}
int main()
{
for (int i=0; i<10; i++)
printf("%f\n", randdouble(-1,3));
}
Output sample:
2.360751
0.577532
2.132397
2.193760
2.646589
-0.209795
0.340891
2.072918
0.111099
1.215880
(note the range: -1..3)
The GNU scientific library has a few methods.
http://www.gnu.org/s/gsl/manual/html_node/Random-number-generator-algorithms.html
Even if you can't use it due to licensing it should give you the names of a few too google for.
The boost random library (C++) uses lagged fibonacci and ranlux algorithms for doubles and floats, so they may be another option for you. (The methods not the boost library as it is C++ )
These techniques usually give you results in the range 0 -- 1. By using R = rmin + v* (rmax-rmin) where v is in 0 -- 1 you will get R in rmin -- rmax
Take a look at Boost.Random:
http://www.boost.org/doc/libs/1_47_0/doc/html/boost_random.html
You can get float random values doing this way:
boost::mt19937 base_rng;
boost::uniform_01<> u01;
boost::variate_generator<boost::mt19937&, boost::uniform_01<> > rng(base_rng, u01);
rng(); // draws a random number
Please note that random number generation facilities are now available in the new C++ standard:
http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01617.html
You can use
rand() / (double)RAND_MAX /* 0 <= random number <= 1 */
rand() / (RAND_MAX + 1.0) /* 0 <= random number < 1 */
for a random number between 0 and 1.
Then multiply by your desired range and add for the initial value.
For instance, to get random numbers 0 <= X < 4.2
double tmp = rand() / (RAND_MAX + 1.0)
X = tmp * 4.2;
to get random numbers -21.1 <= X <= 37.5
double tmp = rand() / (double)RAND_MAX
X = tmp * (37.5 + 21.1);
X = X - 21.1;
The simplest method I know:
int randNum = rand();
float floatRand = randNum/RAND_MAX;
floatRand is a random float in [0,1]. However, the resolution of this method is limited by RAND_MAX..
[EDIT]:
to get negative values, generate another random number and if its greater than RAND_MAX/2, multiply the former by (-1).
This will generate random [any representable float]:
#include <stdio.h>
float randfdev(void)
{
float tmp;
int fd = open("/dev/urandom",O_RDONLY);
read(fd,&tmp,sizeof tmp);
return tmp;
}
Note:
no error checking
assumes IEEE floating point, although other formats should work
will produce NaNs, subnormals, infinitys, etc
Related
So I have this question in statistics that I need to solve using C programming. We have to calculate the values of MSE for various values of theta(population parameter of exponential distribution) and n(sample size. We set theta as constant and calculate MSE for various values of n, and then make n constant and calculate MSE for various theta.
Then we tabulate the results.
This is my program
# include <stdio.h>
# include <math.h>
# include <stdlib.h>
int main(void)
{
int n ,N=5;
float theta,msum =0.0,mse; //paramters
int i,j; // loop
printf("Enter the value of n ");
scanf("%d", &n);
printf("Enter the value of theta ");
scanf("%f ", &theta);
//float u[n], x[n];
//first we fix theta and find MSE for different values of n
for(i=0;i<N;i++)
{
float sum = 0.0;
for(j=0;j<n;j++)
{
//x[j] = (-1/theta)*log(1-(rand()/RAND_MAX));
sum += (-1/theta)*log(1-(rand()/RAND_MAX)); //generates random number from unifrom dist and then converts it to exponential using inverse cdf function
printf("%d%d", i, j);
}
float thetahat = n/sum;
msum += (thetahat - theta)*(thetahat - theta);
}
mse = msum/N;
printf("The MSE with n=%d and theta=%f is %f", n, theta, mse);
return 0;
}
However, this program is not giving any output. I tried multiple IDEs.
Error count is zero. What am I doing wrong?
Use floating point division
rand()/RAND_MAX is int division with a quotient of 0 or 1. Uses 1.0 * rand() / RAND_MAX to coax a floating point division.
Avoid log(0)
log(1-(rand()/RAND_MAX) risks log(0), even with 1.0 * rand() / RAND_MAX. I suspect log(1.0 * (RAND_MAX + 1LL - rand()) / (RAND_MAX + 1LL) will achieve your goal.
Why the space?
The trailing space in scanf("%f ", &theta) obliges scanf() to not return until non-white-space inputs occurs after the number. Drop the space and check the return value.
if (scanf("%f", &theta) != 1) {
; // Handle bad input
}
double vs. float
Code curiously uses float objects, yet double function calls.
Use double as the default floating point type in C unless you have a compelling need for float.
I was calculating e^x using Taylor Series and noticed that when we calculate it for negative x absolute error is large.Is it because we don't have enough precision to calculate it?
(I know that to prevent it we can use e^(-x)=1/e^x)
#include <stdio.h>
#include <math.h>
double Exp(double x);
int main(void)
{
double x;
printf("x=");
scanf("%le", &x);
printf("%le", Exp(x));
return 0;
}
double Exp(double x)
{
double h, eps = 1.e-16, Sum = 1.0;
int i = 2;
h = x;
do
{
Sum += h;
h *= x / i;
i++;
} while (fabs(h) > eps);
return Sum ;
}
For example:
x=-40 the value is 4.24835e-18 but programm gives me 3.116952e-01.The absolute error is ~0.311
x=-50 the value is 1.92875e-22 programm gives me 2.041833e+03.The absolute error is ~2041.833
The problem is caused by rounding errors at the middle phase of the algorithm.
The h is growing quickly as 40/2 * 40/3 * 40 / 4 * ... and oscillating in sign. The values for i, h and Sum for x=-40 for consecutive iterations can be found below (some data points omitted for brevity):
x=-40
i=2 h=800 Sum=-39
i=3 h=-10666.7 Sum=761
i=4 h=106667 Sum=-9905.67
i=5 h=-853333 Sum=96761
i=6 h=5.68889e+06 Sum=-756572
...
i=37 h=-1.37241e+16 Sum=6.63949e+15
i=38 h=1.44464e+16 Sum=-7.08457e+15
i=39 h=-1.48168e+16 Sum=7.36181e+15
i=40 h=1.48168e+16 Sum=-7.45499e+15
i=41 h=-1.44554e+16 Sum=7.36181e+15
i=42 h=1.37671e+16 Sum=-7.09361e+15
i=43 h=-1.28066e+16 Sum=6.67346e+15
i=44 h=1.16423e+16 Sum=-6.13311e+15
i=45 h=-1.03487e+16 Sum=5.50923e+15
i=46 h=8.99891e+15 Sum=-4.83952e+15
...
i=97 h=-2610.22 Sum=1852.36
i=98 h=1065.4 Sum=-757.861
i=99 h=-430.463 Sum=307.534
...
i=138 h=1.75514e-16 Sum=0.311695
i=139 h=-5.05076e-17 Sum=0.311695
3.116952e-01
The peak magnitude of sum is 7e15. This is where the precision is lost. Type double can be represented with about 1e-16 accuracy. This gives expected absolute error of about 0.1 - 1.
As the expected sum (value of exp(-40) is close to zero the final absolute error is close to the maximal absolute error of the partial sums.
For x=-50 the peak value of sum is 1.5e20 what gives the absolute error due to finite representation of double at about 1e3 - 1e4 what is close to observed one.
Not much can be fixed without significant changes to algorithm to avoid forming those partial sums. Alternatively, compute exp(-x) as 1/exp(x).
For negative x, adding the alternating +/- terms creates a computational problems even in the first sum of 1.0 + x as the final sum error can be expected to be as bad as the least significant bit of 1.0 or about 1 part in 1016. This implies x_min as in Exp(x_min) == 1.0e-16 is the minimum useful computational value (e.g. x about -36)
A simple solution is to form a good Exp(positive_x) and for negative values ...
double Exp(double x) {
if (x < 0) {
return 1.0 / Exp(-x);
}
...
A good (and simple) Exp(positive_x) computes terms until a term + 1.0 is still 1.0 as additional small terms do not change the sum significantly. Works well for all x (very small error) except could use improvements when the result should be a sub-normal.
double my_exp(double x) {
if (x < 0) {
return 1.0 / my_exp(-x);
}
double sum = 1.0;
unsigned n = 1;
double term = 1.0;
do {
term *= x / n++;
sum += term;
if (!isfinite(term)) {
return term;
}
} while (1.0 != term + 1.0);
return sum;
}
So I have the distribution f(x) = (4-2x)/3, for x in [0,1], and f(x) = 0 elsewhere.
I now want to generate, say n = 100 random numbers from this distribution. I tried to follow this example, and this is my own code:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <math.h>
#include <stdlib.h>
//pdf(x) = 1 if x>1
// = 0 if x<0
// = 1/3*(4-2x) otherwise
int N = 10;
int var1(int argc, char **argv) {
int p = 0, i;
for (i = 0; i < N; i++) {
p = (double)(rand() % 100)/100; // Generates 100 numbers in [0,1]
if (p > 1)
printf("%d ", 0);
else if (p < 0)
printf("%d ", 0);
else
printf("%f ", p * (4-2*0.1)/3);
}
printf("...");
return 0;
}
However my output is just zeroes:
0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 …
I have two questions:
What am I missing?
In the link I provided, why has he replaced x by 0.1? I just did the same thing but I don't understand why.
First, you're not returning the range of random numbers you think you are:
p = (double)(rand() % 100)/100;
The right hand size will give you a number in the range ( 0.00, 0.01, 0.02 ... 0.99 ). But then you assign that value to p, which is of type int. The fractional part is truncated, so the assigned value will always be 0.
Change the type of p to double to store the proper values. Also, if you want a wider range of random values, use this instead:
p = (double)rand() / RAND_MAX;
As for this:
printf("%f ", p * (4-2*0.1)/3);
Compared to the linked code:
printf("%f ", p * 0.1 / 360);
Their code isn't putting 0.1 in place of x. p is the same as x, but for some reason they're adding the extra 0.1 factor.
For you to be doing f(x) = (4-2x)/3, you need this:
printf("%f ", (4-2*p)/3);
Preamble
The function in the question, f(x) = (4-2x)/3 for x in [0, 1], is a probability density function, not a cumulative distribution function. If the distribution were drawn as a curve with unit area between the x axis and the curve, the probability density function is the slope of that curve, while the cumulative distribution function is the amount of area under the curve up to a certain x.
We can see (4-2x)/3 is not a cumulative distribution function because the cumulative distribution must be 1 at the end of the distribution (∞ in general, but 1 here since the function is zero beyond 1, but (4-2x)/3 is 2/3 at 1. We can see it is a probability density function because its integral (shown below) is 1 at the end of the distribution.
The link given in the question uses a cumulative distribution function. In fact, it is a cumulative distribution function for a uniform distribution over [0, 360]. Because of that, solving the necessary equation (see below) is merely a matter of scaling. This is trivial and does not serve as a general example for generating samples for an arbitrary distribution.
Solution
Given a probability density function, f(x), the corresponding cumulative distribution function, F(x), is the integral of f from −∞ to x. We can use the cumulative distribution function to convert a uniform distribution to the desired distribution.
The integral of (4-2x)/3 is (4x−x2)/3 (plus a constant). Since this is zero at x=0 and f(x) is zero for x < 0, F(x) is also (4x−x2)/3 in [0, 1].
If we have a sample p from a uniform distribution in [0, 1], the point x where the amount of the desired distribution at or below x equals the amount of the uniform distribution at or below p satisfies F(x) = p.
Thus (4x−x2)/3 = p, so x = 2 + sqrt(4−3p).
Thus, given p generated with p = (double) rand() / RAND_MAX, we can find the sample for the desired distribution as 2 + sqrt(4-3*p).
I wrote C program that defined a 2D matrix with m rows and n columns with random numbers (Either 0 or 1). The code is as following:
int i,j;
int original_matrix[m][n];
for (i=0; i<=m-1; i++){
for (j=0; j<=n-1; j++){
original_matrix[i][j] = rand() % 2;
}
}
It worked. For the next step, I want to create the matrix with a probability. For example, 1 is written into a cell with probability p and 0 is written with probability 1-p. Could you please share any ideas on this if you have?
Since rand() gives you a value between 0 and RAND_MAX, you can get a value at particular perentage simply by choosing an appropriate threshold. For example, if RAND_MAX was 999, 42% of all values would be expected to be less than 420.
So you can use code like in the following complete program, to set up an appropriate threshold and test the distribution of your values:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int main(int argc, char *argv[]) {
// Get threshold (defaults to ~PI%), seed random numbers.
double percent = (argc > 1) ? atof(argv[1]) : .0314159;
int threshold = round(RAND_MAX * percent);
srand(time(0));
// Work out distribution (millions of samples).
int below = 0, total = 0;
for (int i = 0 ; i < 1000000; ++i) {
++total;
if (rand() < threshold) ++below;
}
// Output stats.
printf("Using probability of %f, below was %d / %d, %f%%\n",
percent, below, total, below * 100.0 / total);
}
Some sample runs, with varying desired probabilities:
Using probability of 0.031416, below was 31276 / 1000000, 3.127600%
Using probability of 0.031416, below was 31521 / 1000000, 3.152100%
Using probability of 0.421230, below was 420936 / 1000000, 42.093600%
Using probability of 0.421230, below was 421634 / 1000000, 42.163400%
Using probability of 0.175550, below was 175441 / 1000000, 17.544100%
Using probability of 0.175550, below was 176031 / 1000000, 17.603100%
Using probability of 0.980000, below was 979851 / 1000000, 97.985100%
Using probability of 0.980000, below was 980032 / 1000000, 98.003200%
Using probability of 0.000000, below was 0 / 1000000, 0.000000%
Using probability of 1.000000, below was 1000000 / 1000000, 100.000000%
So, the bottom line is: to acheive your desire of one having a probabilty p (a double value) and zero having the probability 1 - p, you need the following:
srand(time(0)); // done once, seed generator.
int threshold = round(RAND_MAX * p); // done once.
int oneOrZero = (rand() < threshold) ? 1 : 0; // done for each cell.
Just keep in mind the limits of rand(), the difference between (for example) probabilities 0.0000000000 and 0.0000000001 will most likely be non-existent, unless RAND_MAX is large enough to make a difference. I doubt you'll be using probabilities that fine but I thought I'd better mention it just in case.
rand() % 2 gives you a probability of 0.5.
p is a float, so you'll look at How to generate random float number in C to generate a random value in a real range. The top answer gives us: float x = (float)rand()/(float)(RAND_MAX/a);
We want a equal to 1 for probabilities. So, to get 0 with a probability of p, the formula is:
int zeroWithAProbabilityOfP = (float)rand()/(float)RAND_MAX <= p;
Which can be also be written:
int zeroWithAProbabilityOfP = rand() <= p * RAND_MAX;
ps: if available, for precision reasons, you should favor arc4random() or arc4random_buf() instead of rand():
rand() precision is 1 / 0x7FFFFFFF (on macOS)
arc4random() precision is 1 / 0xFFFFFFFF (so twice better)
In that case, formula would be:
int zeroWithAProbabilityOfP = arc4random() <= p * UINT32_MAX;
I'm trying to calculate the the taylor series of cos(x) with error at most 10^-3 and for all x ∈ [-pi/4, pi/4], that means my error needs to be less than 0.001. I can modify the x +=in the for loop to have different result. I tried several numbers but it never turns to an error less than 0.001.
#include <stdio.h>
#include <math.h>
float cosine(float x, int j)
{
float val = 1;
for (int k = j - 1; k >= 0; --k)
val = 1 - x*x/(2*k+2)/(2*k+1)*val;
return val;
}
int main( void )
{
for( double x = 0; x <= PI/4; x += 0.9999 )
{
if(cosine(x, 2) <= 0.001)
{
printf("cos(x) : %10g %10g %10g\n", x, cos(x), cosine(x, 2));
}
printf("cos(x) : %10g %10g %10g\n", x, cos(x), cosine(x, 2));
}
return 0;
}
I'm also doing this for e^x too. For this part, x must in [-2,2] .
float exponential(int n, float x)
{
float sum = 1.0f; // initialize sum of series
for (int i = n - 1; i > 0; --i )
sum = 1 + x * sum / i;
return sum;
}
int main( void )
{
// change the number of x in for loop so you can have different range
for( float x = -2.0f; x <= 2.0f; x += 1.587 )
{
// change the frist parameter to have different n value
if(exponential(5, x) <= 0.001)
{
printf("e^x = %f\n", exponential(5, x));
}
printf("e^x = %f\n", exponential(5, x));
}
return 0;
}
But whenever I changed the number of terms in the for loop, it always have an error that is greater than 1. How am I suppose to change it to have errors less than 10^-3?
Thanks!
My understanding is that to increase precision, you would need to consider more terms in the Taylor series. For example, consider what happens when
you attempt to calculate e(1) by a Taylor series.
$e(x) = \sum\limits_{n=0}^{\infty} frac{x^n}{n!}$
we can consider the first few terms in the expansion of e(1):
n value of nth term sum
0 x^0/0! = 1 1
1 x^1/1! = 1 2
2 x^2/2! = 0.5 2.5
3 x^3/3! = 0.16667 2.66667
4 x^4/4! = 0.04167 2.70834
You should notice two things, first that as we add more terms we are getting closer to the exact value of e(1), also that the difference between consecutive sums are getting smaller.
So, an implementation of e(x) could be written as:
#include <stdbool.h>
#include <stdio.h>
#include <math.h>
typedef float (*term)(int, int);
float evalSum(int, int, int, term);
float expTerm(int, int);
int fact(int);
int mypow(int, int);
bool sgn(float);
const int maxTerm = 10; // number of terms to evaluate in series
const float epsilon = 0.001; // the accepted error
int main(void)
{
// change these values to modify the range and increment
float start = -2;
float end = 2;
float inc = 1;
for(int x = start; x <= end; x += inc)
{
float value = 0;
float prev = 0;
for(int ndx = 0; ndx < maxTerm; ndx++)
{
value = evalSum(0, ndx, x, expTerm);
float diff = fabs(value-prev);
if((sgn(value) && sgn(prev)) && (diff < epsilon))
break;
else
prev = value;
}
printf("the approximate value of exp(%d) is %f\n", x, value);
}
return 0;
}
I've used as a guess that we will not need to use more then ten terms in the expansion to get to the desired precision, thus the inner for loop is where we loop over values of n in the range [0,10].
Also, we have several lines dedicated to checking if we reach the required precision. First I calculate the absolute value of the difference between the current evaluation and the previous evaluation, and take the absolute difference. Checking if the difference is less than our epsilon value (1E-3) is on of the criteria to exit the loop early. I also needed to check that the sign of of the current and the previous values were the same due to some fluctuation in calculating the value of e(-1), that is what the first clause in the conditional is doing.
float evalSum(int start, int end, int val, term fnct)
{
float sum = 0;
for(int n = start; n <= end; n++)
{
sum += fnct(n, val);
}
return sum;
}
This is a utility function that I wrote to evaluate the first n-terms of a series. start is the starting value (which is this code always 0), and end is the ending value. The final parameter is a pointer to a function that represents how to calculate a given term. In this code, fnct can be a pointer to any function that takes to integer parameters and returns a float.
float expTerm(int n, int x)
{
return (float)mypow(x,n)/(float)fact(n);
}
Buried down in this one-line function is where most of the work happens. This function represents the closed form of a Taylor expansion for e(n). Looking carefully at the above, you should be able to see that we are calculating $\fract{x^n}{n!}$ for a given value of x and n. As a hint, for doing the cosine part you would need to create a function to evaluate the closed for a term in the Taylor expansion of cos. This is given by $(-1)^n\fact{x^{2n}}{(2n)!}$.
int fact(int n)
{
if(0 == n)
return 1; // by defination
else if(1 == n)
return 1;
else
return n*fact(n-1);
}
This is just a standard implementation of the factorial function. Nothing special to see here.
int mypow(int base, int exp)
{
int result = 1;
while(exp)
{
if(exp&1) // b&1 quick check for odd power
{
result *= base;
}
exp >>=1; // exp >>= 1 quick division by 2
base *= base;
}
return result;
}
A custom function for doing exponentiation. We certainly could have used the version from <math.h>, but because I knew we would only be doing integer powers we could write an optimized version. Hint: in doing cosine you probably will need to use the version from <math.h> to work with floating point bases.
bool sgn(float x)
{
if(x < 0) return false;
else return true;
}
An incredibly simple function to determine the sign of a floating point value, returning true is positive and false otherwise.
This code was compiled on my Ubuntu-14.04 using gcc version 4.8.4:
******#crossbow:~/personal/projects$ gcc -std=c99 -pedantic -Wall series.c -o series
******#crossbow:~/personal/projects$ ./series
the approximate value of exp(-2) is 0.135097
the approximate value of exp(-1) is 0.367857
the approximate value of exp(0) is 1.000000
the approximate value of exp(1) is 2.718254
the approximate value of exp(2) is 7.388713
The expected values, as given by using bc are:
******#crossbow:~$ bc -l
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
e(-2)
.13533528323661269189
e(-1)
.36787944117144232159
e(0)
1.00000000000000000000
e(1)
2.71828182845904523536
e(2)
7.38905609893065022723
As you can see, the values are well within the tolerances that you requests. I leave it as an exercise to do the cosine part.
Hope this helps,
-T
exp and cos have power series that converge everywhere on the real line. For any bounded interval, e.g. [-pi/4, pi/4] or [-2, 2], the power series converge not just pointwise, but uniformly to exp and cos.
Pointwise convergence means that for any x in the region, and any epsilon > 0, you can pick a large enough N so that the approximation you get from the first N terms of the taylor series is within epsilon of the true value. However, with pointwise convergence, the N may be small for some x's and large for others, and since there are infinitely many x's there may be no finite N that accommodates them all. For some functions that really is what happens sometimes.
Uniform convergence means that for any epsilon > 0, you can pick a large enough N so that the approximation is within epsilon for EVERY x in the region. That's the kind of approximation that you are looking for, and you are guaranteed that that's the kind of convergence that you have.
In principle you could look at one of the proofs that exp, cos are uniformly convergent on any finite domain, sit down and say "what if we take epsilon = .001, and the regions to be ...", and compute some finite bound on N using a pen and paper. However most of these proofs will use at some steps some estimates that aren't sharp, so the value of N that you compute will be larger than necessary -- maybe a lot larger. It would be simpler to just implement it for N being a variable, then check the values using a for-loop like you did in your code, and see how large you have to make it so that the error is less than .001 everywhere.
So, I can't tell what the right value of N you need to pick is, but the math guarantees that if you keep trying larger values eventually you will find one that works.