• Welcome to the new Internet Infidels Discussion Board, formerly Talk Freethought.

The Programming Thread

lpetrich, Some systems had full float arithmetics without integer multiplication-division.
Nowadays
SPARC initially no integer multiply or divide, later got those instructions. Floating point always
Yes, I had one - full float arithmetics without integer multiplication-division.
Of course, it was a separate giant FPU chip, cpu itself was pretty small.
 
An historical footnote in math computing.

They did it initially without large scale integrated circuits. In the 80s at a Lockheed division nobody had PCs, we had terminals connected to DEC VAX computers. When I ran code if I wmated to use the math compressor the group was charged more for the CPU time.



Floating Point Systems, Inc. (FPS), was a Beaverton, Oregon vendor of attached array processors and minisupercomputers. The company was founded in 1970 by former Tektronix engineer Norm Winningstad,[1] with partners Tom Prince, Frank Bouton and Robert Carter. Carter was a salesman for Data General Corp. who persuaded Bouton and Prince to leave Tektronix to start the new company. Winningstad was the fourth partner.[2]
History

The original goal of the company was to supply economical, but high-performance, floating point coprocessors for minicomputers. In 1976, the AP-120B array processor was produced. This was soon followed by a unit for larger systems and IBM mainframes, the FPS AP-190. In 1981, the follow-on FPS-164 was produced, followed by the FPS-264, which had the same architecture. This was five times faster, using ECL instead of TTL chips.

These processors were widely used as attached processors for scientific applications in reflection seismology, physical chemistry, NSA cryptology and other disciplines requiring large numbers of computations. Attached array processors were usually used in facilities where larger supercomputers were either not needed or not affordable. Hundreds if not thousands of FPS boxes were delivered and highly regarded. FPS's primary competition up to this time was IBM (3838 array processor) and CSP Inc.

Cornell University, led by physicist Kenneth G. Wilson, made a supercomputer proposal to NSF with IBM to produce a processor array of FPS boxes attached to an IBM mainframe with the name lCAP.
 
 Floating Point Systems - I remember its computers from long ago, hosted by an IBM mainframe. I'd compile code for them with a cross-compiler on the host system. FPS's computers were  Vector processor ones, with instructions that do the same thing on the contents of a sequence of memory locations. These were common in the 1970's to 1990's, but they went into decline as more conventional chips because cheap competition for them.

Vector processing is a SIMD sort of operation, and variable-length, while the most common form of SIMD in CPU chips is fixed-length, like MMX and SSE for x86.
 
In the late 70s I was a field engineer for Automatic Data Procession corp.

I maintained Microdata mini computers. The CPU was a made with discrete logic chips, bit slice. You could actually trouble shoot and repair the CPU.

 
Installed gnuplot. Easy install.

It is command line but callable from Python and C/C++ system functions.

Python has a module that interfaces.
 
Gnuplot is fussy about data file encoding.

When I used Python to create data sets to plot, gnuplot would not correctly read the file unless I explicitly defined utf-8 when opening the file.

wgnuplot.exe has a window with pull down menus.
 
Using Gnuplot from Python and C. Gnuplot has the C operators and can function as a calcultor.

Gnuplot script files are .plt and data files .dat.

Python

import os
os.chdir('c:\\python')
os.system('sig.plt')

C
system("sig.plt");

A project would be to create class objects to set the Gnuplot variables and create a .plt file.

sig.plt, copied it from a Gnuplot demo file.

reset
set term windows
set autoscale xfixmin # axis range automatically scaled to include the range
set autoscale xfixmax # of data to be plotted
set tics font ",18"
set xlabel "x" font ",18"
set ylabel "y" font ",18"
set lmargin at screen 0.1 # set size of left margin
set rmargin at screen 0.82 # set size of right margin
set bmargin at screen 0.12 # set size of bottom margin
set tmargin at screen 0.95 # set size of top margin
set grid
plot 'sig.dat'
 
A function that takes an arbitrary number of int and double arrays and prints on the console.

The format string rakes ints, doubles, and the the %e display specifier.

Code:
#include<stdarg.h>
#include <strings.h>

void print_arrays(int nrow,char *prspec, ...){
    //print arrays of same length to the console
    // prpec forma stringas as in printf()
    // narg numer of arrays passed to function,
    //picnt pdcnt counters for number of int and double array pointers
    // pi pd arrays of pointers to arrays
    cout<<"print arrays "<<endl;
    int i,j,narg = 0,picnt = 0,pdcnt = 0;
    int * pi[20];
    double *pd[20];
    //--------------------------------------
    //split format string into substrigs for printf()
    char fdel[2] = " ";  //split delimiter
    char pfmt[10][10];
    char * token = strtok(prspec,fdel);
    while( token != NULL ) {
        strcpy(pfmt[narg++],token);
        //printf( " %s\n", token ); //printing each token
        token = strtok(NULL, fdel);
    }
   //-------------------------------------
   // make var_args format string
   int nfmt = 100;
   char *fmt = new char[nfmt];
   for(i=0;i<nfmt;i++)fmt[i] = '\0'; //null the array so strcat() starts at fmt[0]
   for(i=0;i<narg;i++){
        if(strchr(pfmt[i],'d') != NULL)strcat(fmt," d");
        if(strchr(pfmt[i],'f') != NULL)strcat(fmt," f");
        if(strchr(pfmt[i],'e') != NULL)strcat(fmt," f");
   }
   //cout<<"fmt   "<<fmt<<endl;
    //--------------------------------------
    //get pointers to arrays
    va_list args;
    va_start(args, fmt);
    while (*fmt != '\0') {
        if(*fmt == 'd')pi[picnt++] = va_arg(args, int*);
        if(*fmt == 'f')pd[pdcnt++] = va_arg(args, double*);
        if(*fmt == 'e')pd[pdcnt++] = va_arg(args, double*);
        //cout<<*fmt;
       ++fmt;
        }//while
      //cout<<endl;
    va_end(args);
    //printf("counts  %d  %d\n",picnt,pdcnt);
    //--------------------------------------------
    //print arrays
    for(i = 0;i<nrow;i++){
        picnt = 0;
        pdcnt = 0;
        for(j=0;j<narg;j++){
            if(strchr(pfmt[j],'d') != NULL)printf(pfmt[j],*(pi[picnt++]+i));
            if(strchr(pfmt[j],'f') != NULL)printf(pfmt[j],*(pd[pdcnt++]+i));
            if(strchr(pfmt[j],'e') != NULL)printf(pfmt[j],*(pd[pdcnt++]+i));
            if(j<narg-1)printf("\t"); //no tab after last column
            }//for j
        printf("\n");
        }//for i
}//print_arrays()

int main(){
    int n = 4;
    int xi2[n] = {10,20,30,40},xi1[n] = {1,2,3,4};
    double xd1[n] = {1.1,2.2,3.3,4.1};
    double xd2[n] = {10.1,20.2,30.3,40.4};
    char fmt[] = "%10d %5.3f %5d %1.2e";
    print_arrays(n,fmt,xi1,xd1,xi2,xd2);


    return 0;
}
 
The Fqst Fourier Transform is one of the most important pieces of applied math.

I think it s out of print but there are PDFs. Scroll down to chapter 8.


The original Cooley Tukey paper.




The algorithm is common. It is in place from the days of limited memory. The real signal array into the algorithm is overwritten with he real part of the transform to save the memory for 3 arrays.

For the forward transform I copy the input real signal to the real part of compx trasform array presevng the signal.

For the inverse transform I copy the complex transform in and restore it at the end.

The algorithm takes advantage of con points in the Discrete Fourier Transform. Smaller DFTs are performed and outputs are inputs into the next transform, but not 1 to 1,

The output of transform has to be unscrambled, bit shifting.

The C time() function is not very good, as far as I can tell a 2^18 transform takes about 30 milliseconds.

The inverse transform takes the complex out of the forward transform and reconstructs the input signal.

It us a power of 2 algorithm, zeros ca b added to a record hat is not 2^n in length.

I used Gnuplot. It has to be installed but does not have to be running.

The scale() function creates the time and frequency scales.

mag_phase() computes the magnitude and phase of the complex transform.

As is the signal is a square wave.

Code:
//fft class
#include <iostream>
#include "stdlib.h"
#include "stdio.h"
#include <complex>
using namespace std;
typedef complex<double> compvar;
const double _PI=  3.14159265358979323846;

class FFT{
    public:
    int n = 0;
    compvar *tfc;
    double *t,*y ,*freqs,*mag,*phase,fs;
    int ffti(void);
    int fft(void);
    void scale(void);
    void mag_phase(void);

};//FFT


void FFT::scale(void){
    int i;
    double dt = 1./fs,df = fs/n,f = 0;
    for(i=0;i<n;i++){
        t[i] = i * dt;
        freqs[i] = f;
        f += df;
        }
}//fft_scale()

void FFT::mag_phase(void){
    int i;
    for(i=0;i<n;i++){
        if(i==0){
            mag[0] = real(tfc[0])/n;
            phase[0] = 0;
            }
        else{
            mag[i] = 2*abs(tfc[i])/n;
            phase[i] = atan(imag(tfc[i])/real(tfc[i]))*180./_PI;
            }
    }
}//mag_phase()


int FFT::fft(void){
    // n length of transform power of 2
    // y real input signal
    // tfc  compplex transform out
    cout<<"FFT Forward"<<endl;
    if(n%2 != 0){cout<<"Not Power Of 2  "<<endl;return 1;}
    compvar w,temp;
    int i,j,k,n1,n2,a;
    int m = log(n)/log(2); //exponet of 2^m
    for(i=0;i<n;i++)tfc[i] = y[i] + 0.i;
    // Bit reversal
    j = 0; n2 = n/2;
    for (i=1; i < n - 1; i++) {
        n1 = n2;
        while ( j >= n1 ) {j = j - n1;n1 = n1/2;}
        j = j + n1;
        if (i < j) {temp = tfc[i];tfc[i] = tfc[j];tfc[j] = temp;}
    }//i

    // Transform
    n1 = 0;n2 = 1;
    for (i=0; i < m; i++) {
        n1 = n2;n2 += n2;a = 0;
        for (j=0; j < n1; j++) {
            w = exp(-2.i*_PI*double(a)/double(n)); //smpled sine wave
            a += 1 << (m-i-1);
            for (k=j; k < n; k=k+n2) {
                temp = tfc[k+n1]*w;
                tfc[k+n1] = tfc[k] - temp;
                tfc[k] = tfc[k] + temp;
            }//k
        }//j
    }//i
    return 0;
}//fft()

int FFT::ffti(void){
    // n length otransform power of 2
    // yr real input signal
    // tfc  compplex transform out
    cout<<"FFT Inverse"<<endl;
    if(n%2 != 0){cout<<"Not Power Of 2  "<<endl;return 1;}
    double tre,tim;
    compvar w,temp;
    compvar *tfcc = new compvar[n];
    int i,j,k,n1,n2,a;
    int m = log(n)/log(2); //exponet of 2^m
    for(i=0;i<n;i++)tfcc[i] = tfc[i];

    // Bit reversal
    j = 0; n2 = n/2;
    for (i=1; i < n - 1; i++) {
        n1 = n2;
        while ( j >= n1 ) {j = j - n1;n1 = n1/2;}
        j = j + n1;
        if (i < j) {temp = tfc[i];tfc[i] = tfc[j];tfc[j] = temp;}
    }//i

    // Transform
    n1 = 0;n2 = 1;
    for (i=0; i < m; i++) {
        n1 = n2;n2 += n2;a = 0;
        for (j=0; j < n1; j++) {
            w = exp(2.i*_PI*double(a)/double(n));
            a += 1 << (m-i-1);
            for (k=j; k < n; k=k+n2) {
                temp = tfc[k+n1]*w;
                tfc[k+n1] = tfc[k] - temp;
                tfc[k] = tfc[k] + temp;
                y[k+n1] = real(tfc[k+n1])/n;
                y[k] = real(tfc[k])/n;
            }//k
        }//j
    }//i
    for(i=0;i<n;i++)tfc[i] = tfcc[i];
    delete [] tfcc;
    return 0;
}//ffti()
 
Code:
#include <iostream>
#include "stdlib.h"
#include "stdio.h"
#include <complex>
using namespace std;


const double _PI=  3.14159265358979323846;
typedef complex<double> compvar;
int nmax = pow(2,18);
compvar *tfc = new compvar[nmax];
double *yr = new double[nmax];
double *yi = new double[nmax];
double *mag = new double[nmax];
double *ph = new double[nmax];
double *t = new double[nmax];
double *f = new double[nmax];

int save_fft(int n,double *f,double *mag,double *phase,double *t,double *yr,double *yi){
    cout<<"Save  "<<endl;
    int i;
    FILE *p1 = fopen("fft.dat","w");
    FILE *p2 = fopen("signals.dat","w");
    if(!p1 || !p2){cout<<"fail";return 1;}
    for(i=0;i<n;i++){
        fprintf(p1,"% .20f  %.20f   %.20f\n",f[i],mag[i],phase[i]);
        fprintf(p2,"% .20f   %.20f   %.20f\n",t[i],yr[i],yi[i]);
        }
    fclose(p1);fclose(p2);
    return 0;
}//save()

class FFT{
    public:
    int n = 0;
    compvar *tfc;
    double *t,*y ,*freqs,*mag,*phase,fs;
    int ffti(void);
    int fft(void);
    void scale(void);
    void mag_phase(void);
};

void am(int n,double *t,double *y,double fc,double fm,double m,double a){
   //amplitude modulation
    int i;
    for(i=0;i<n;i++)y[i] = (a+m*cos(2*_PI*fm*t[i]))*sin(2*_PI*fc*t[i]);
}

void rect(int n,double *t,double *y,double tlo,double thi,
                    double vlo,double vhi){
    // recngular wave
    double dt = t[2]-t[1], tcount = 0;
    int i = 0;
    while(1){
        tcount = 0;
        while(tcount <= thi) {
            if(i == n) break;
            y[i] = vhi;tcount += dt;i += 1;}
        tcount = 0;
        while(tcount <= tlo){
            if(i == n) break;
            y[i] = vlo ;tcount += dt;i +=  1;}
        if(i == n) break;
     }
}//rect()

int main(void){
    int i,n = pow(2,16);
    cout<<n<<endl;
    FFT fft;
    fft.n = n;fft.fs = 1000;fft.t = t;
    fft.y = yr;fft.tfc = tfc;fft.freqs = f;fft.mag = mag;fft.phase = ph;
    fft.scale();
    rect(n,t,yr,.025,.025,-1,1);
    //am(n,t,yr,100,20,.8,4);
   //for(i=0;i<n;i++)yr[i] = sin(2*_PI*20*t[i])-2; //sine wave
    fft.fft();
    fft.y = yi;
    fft.ffti();
    fft.mag_phase();
    save_fft(n,f,mag,ph,t,yr,yi);
    //excute Gnuplot scripts
    string  fnfft = path + "fft.plt";
    string  fnsig = path + "signals.plt";
    system(fnfft.c_str());
    system(fnsig.c_str());
return 0;
 
Gnuplot scripts

fft.plt

term windows background rgb "white" title "DFT" fontscale 1
reset
set multiplot layout 2,1 columnsfirst

set grid lt 1 lw 1 lc rgb "black" dashtype solid

# magnitude
set autoscale y
show autoscale
set zeroaxis
set xrange[0:500]
set ylabel "MAGNITUDE"
plot 'fft.dat' using 1:2 with lines ls 4 lt -1 lw 3
unset autoscale y

# phase
set zeroaxis
set xrange[0:500]
set yrange[-90:90]
set xlabel "FREQUENCY"
set ylabel "PHASE"
plot 'fft.dat' using 1:3 with lines ls 4 lt -1 lw 3

show grid
unset multiplot

signals.plt

set term windows background rgb "white" title "SIGNALS" fontscale 1
reset
set multiplot layout 2,1 columnsfirst

set grid lt 1 lw 1 lc rgb "black" dashtype solid
# signal
set autoscale y
show autoscale
set zeroaxis
set xrange[0:1]
set yrange[-4:4]
plot 'signals.dat' using 1:2 with lines ls 4 lt -1 lw 3
show grid
unset autoscale y

#inverse
set zeroaxis
set xrange[0:1]
set yrange[-4:4]
set xlabel "seconds"
plot 'signals.dat' using 1:3 with lines ls 4 lt -1 lw 3

show grid
unset multiplot
 
Interrogating Gnuplot with C++.

If Gnupolt is installed clicking on a .plt file will execute the plot script. S0o the C system() command will run a plot file.

All yiou have to do is have an object that creates a Gnuplt text file based on parmeters, and executing it.

A simple XY plot.


Code:
int save(int n,double *x,double *y,string fname){
    int i;
    ofstream ofile;
    ofile.open(fname);
    if(!ofile) return 1;
    ofile<<setprecision(10);
    for(i=0;i<n;i++)ofile<<x[i]<<setw(10)<<"\t"<<y[i]<<endl;
    ofile.close();
    return 0;
}//save()

class GNUPLOTXY{
    public:
    string xlo,xhi,ylo,yhi;
    string plot_file = "gnp.plt";
    string data_file = "signals.dat";
    int save(void);
    void plot(void);

};

int GNUPLOTXY::save(void){
    int i,n = 7;
    string s[n];
    s[0] = "set term windows background rgb 'white' fontscale 1 \n";
    s[1] = "reset\n";
    s[2] = "set grid lt 1 lw 1 lc rgb 'black'  dashtype solid\n";
    s[3] = "set zeroaxis\n";
    s[4] =   "set xrange["+xlo+":"+xhi+"]\n";
    s[5] =  "set yrange["+ylo+":"+yhi+"]\n";
    s[6] =  "plot '" + data_file + "' using 1:2 with lines ls 4 lt  -1 lw 3\n";

    ofstream ofile;
    ofile.open(plot_file);
    if(!ofile) return 1;
    for(i=0;i<n;i++)ofile<<s[i];
    ofile.close();
    return 0;
}

void GNUPLOTXY::plot(void){system(plot_file.c_str());}

int main()
{
    GNUPLOTXY gp;
    int i,n = 200;
    double t[n],y[n],dt = 1./(n-1);
    for(i=0;i<n;i++){
        t[i] = i*dt;
         y[i] = sin(2*_PI*t[i]);
         }
    save(n,t, y,"sig.dat");
    gp.plot_file = "gp.plt";
    gp.data_file = "sig.dat";
    gp.xlo = '0';gp.xhi = "1";
    gp.ylo = "-1";gp.yhi = "1";
    gp.save();
    gp.plot();
    return 0;
}

gp.plt
set term windows background rgb 'white' fontscale 1
reset
set grid lt 1 lw 1 lc rgb 'black' dashtype solid
set zeroaxis
set xrange[0:1]
set yrange[-1:1]
plot 'sig.dat' using 1:2 with lines ls 4 lt -1 lw 3
 
A replacement for C rand() using the URAND algorithm.

The replacement int function has a max random number 2147483646 versus 32767 for the C rand() function.

To compare the decimal methods I broke up the interval 0 to < 1 into 10 bins. For 10^9 insertions hits within each bin were were counted. The iterations were a power of 10 so for a theoretically perfect uniform distribution each bin would have (n iterations)/10 counts. The percent deviation for each bin was calculated and the average calculated. To look for bias in the bins would require a lot of run time.

The URAND algorithm is about an order of magnitude closer to theoretical than C rand(). The averaged results were consistent over multiple runs.

The rand()function requires a separate function srand() to seed the generator.The URAND functions use an old technique to get rid of a second function and global variables,

On the first call to rand_dec() and rand_int() seed is stored in a static variable. On following calls the generator is reseeded only if the seed value changes.

Also the higher max random number for URAND and the finer resolution gets the max decimal number closer to 1.


URAND
Average percent deviation 0.0068779000
Min 0.0000000000 Max 0.9999999972
counts, percent deviation
99996645 -0.003355
100002948 +0.002948
100011698 +0.011698
100006394 +0.006394
99992352 -0.007648
100004694 +0.004694
99999664 -0.000336
99988985 -0.011015
99987964 -0.012036
100008655 +0.008655


C rand()
Average percent deviation 0.0172210000
Min 0.0000000000 Max 0.9999389648
counts, percent deviation
99973671 -0.026329
99993510 -0.006490
100013854 +0.013854
99998121 -0.001879
99968725 -0.031275
100009712 +0.009712
100017827 +0.017827
99997727 -0.002273
100014186 +0.014186
99951615 -0.048385


Code:
int rand_int(unsigned seed){
    //uniform distribution ints 0 - 2147483646
    static unsigned rand_num = 1;
    unsigned m  = 0x7fffffff;
    unsigned k1 = 2*floor(m*(.5 - sqrt(3)/6.)) + 1;
    unsigned k2 = 8*ceil(m*atan(1.)/8.) + 5;
    static unsigned temp_seed = 1;
    if(seed != temp_seed){
        temp_seed = seed;
        rand_num = seed;
       }
    rand_num = rand_num*k2 + k1;
    return rand_num%m;
}

double rand_dec(unsigned seed){
    // unform distribution decimals  0 <= x < 1
    static unsigned rand_num = 1;
    unsigned m  = 0x7fffffff;
    unsigned k1 = 2*floor(m*(.5 - sqrt(3)/6.)) + 1;
    unsigned k2 = 8*ceil(m*atan(1.)/8.) + 5;
    static unsigned temp_seed = 1;
    if(seed != temp_seed){
        temp_seed = seed;
        rand_num = seed;
       }
    rand_num = rand_num*k2 + k1;
    return double(rand_num%m)/(m+1);
}

void rand_dec_test(void){
    cout<<"rand_dec_test"<<endl;
    long long i,n = pow(10,9);
    double k = double(n)/10.,s = 0;
    double x,min,max,pc[10];
    int count[10];
    for(i=0;i<10;i++)count[i] = 0;
    min =1;
    max = 0;
    unsigned seed = time(NULL);
    srand(seed);
    for(i=0;i<n;i++){
        //x = rand_dec(seed);
        x = (double(rand()%RAND_MAX))/double(RAND_MAX+1);
        if(x> 0     && x < .1)count[0]++;
        if(x >= .1 && x < .2)count[1]++;
        if(x >= .2 && x < .3)count[2]++;
        if(x >= .3 && x < .4)count[3]++;
        if(x >= .4 && x < .5)count[4]++;
        if(x >= .5 && x < .6)count[5]++;
        if(x >=  .6 && x < .7)count[6]++;
        if(x >=  .7 && x < .8)count[7]++;
        if(x >=  .8 && x < .9)count[8]++;
        if(x >=  .9 && x <1.)count[9]++;
        if(x > max)max = x;
        if(x < min)min = x;
    }
    for(i=0;i<10;i++){
        pc[i] = 100*(double(count[i]) - k)/k;
        s += abs(pc[i]);
        }
    s = s/10; //average deviation
    for(i=0;i<10;i++)printf("%10d \t%+.5f\n",count[i],pc[i]);
    printf("\nAverage Deviation %.5f\n",s);
    printf(" min  %.15f   max  %.15f\n",min,max);

}//rand_dec_test()

int main(){
    cout<<"RUNNING"<<endl;
    rand_dec_test();
return 0;
 
Moving on to C++ rand


The degree of randomness from my simple test is on the the degree of uniform randomness for the mt19937_64 generator is on the order of URAND. About 0.005%

There are multiple engines including a hardware based crypto option.


Code:
#include <random>
#include <chrono>
using namespace std;
int main(){
    int i, n=100,yi[100];
    double yd[100];
    typedef mt19937_64 default_random_engine;
    unsigned seed = chrono::system_clock::now().time_since_epoch().count();
    default_random_engine generator (seed);
    uniform_real_distribution<double> distr1 (0,1.);
   uniform_int_distribution<int> distr2 (-5,5);
    for(i=0;i<n;i++) {
        yi[i] = distr2(generator) ;
        yd[i] = distr1(generator) ;
        }
    for(i=0;i<n;i++)printf("%+5d \t %+5.15f\n",yi[i],yd[i]);
    return 0; 
}
 
C++ Normal, Exponential Distributions


Code:
#include <random>
#include <chrono>


void save(int n,string fname, double *x1,double *x2){
    int i;
    FILE *p = fopen(fname.c_str(),"w");
    for(i=0;i<n;i++)fprintf(p,"%.10f\t %.10f\t \n",x1[i],x2[i]);
    fclose(p);
}//save()

int comp_doub_ascend(const void * a, const void * b) {
  if (*(double*)a > *(double*)b) return 1;
  else if (*(double*)a < *(double*)b) return -1;
  else return 0;
}

void cum_dist(int n,double *y,double *cd){
    int i;
    qsort(y,n,sizeof(double),comp_doub_ascend);
    for(i = 0;i < n;i++)cd[i] = 100.* double(i)/double(n-1);
}//cum_dist()

double median(int n,double *y){
    //y is sorted ascending
    int i ;
    double c;
    for(i=0;i<n;i++){
        c = double(i)/double(n-1);
        if(c >= 0.5)break;
        }
    return y[i];
}//median()


double avg(int n,double *y){
    int i;
    double s = 0,av;
    for(i=0;i<n;i++)s += y[i];
    return s/double(n);
}//avg()

double sdev(int n,double *y){
    int i;
    double s = 0,av;
     for(i=0;i<n;i++)s += y[i];
    av = s/double(n);
    s = 0;
    for(i=0;i<n;i++)s += pow(av-y[i],2);
   return sqrt(s/double(n));
}//sdev()

double minf(int n,double *y){
    int i;
    double ymin = y[0];
    for(i=0;i<n;i++)if(y[i] < ymin)ymin = y[i];
    return ymin;
}

double maxf(int n,double *y){
    int i;
    double ymax = y[0];
    for(i=0;i<n;i++)if(y[i] > ymax)ymax = y[i];
    return ymax;
}

void normal(int n,double u,double std,double *y){
    int i;
    unsigned seed = chrono::system_clock::now().time_since_epoch().count();
    default_random_engine generator (seed);
    normal_distribution<double> dist(u, std);
    for(i=0;i<n;i++)y[i] = dist(generator);
}

void expon(int n,double mean,double *y){
    int i;
    unsigned seed = chrono::system_clock::now().time_since_epoch().count();
    default_random_engine generator (seed);
    exponential_distribution<double> dist(1./mean);
    for(i=0;i<n;i++)y[i] = dist(generator);
}

int main(){
    int n2=10000;
    int i, n =100,yi[n];
    double *yn = new double[n2];
    double *ye = new double[n2];
    double *cde = new double[n2];
    double *cdn = new double[n2];
    double minn,maxn,mine,maxe;
    double avgn,stdn,medn,avge,stde,mede;

    normal(n2,125,20,yn);
    expon(n2,20,ye);
    cum_dist(n2,ye,cde);
    avgn = avg(n2,yn);
    cum_dist(n2,ye,cde);
    cum_dist(n2,yn,cdn);
    stdn = sdev(n2,yn);
    medn = median(n2,yn);
    minn = minf(n2,yn);
    maxn = maxf(n2,yn);
    printf("normal %.5f \t %.5f \t %.5f \t %.5f\n",avgn,stdn,medn,(maxn-minn)/stdn);
    avge = avg(n2,ye);
    stde = sdev(n2,ye);
    mede = median(n2,ye);
    printf("exponential %.5f \t %.5f \t %.5f  %.5f\n",avge,stde,mede,log(2)*avge);
    save(n2,"norm.dat", yn,cdn);
    save(n2,"exp.dat", ye,cde);
  
  return 0;
}
 
There is a problem with code like this:
Code:
    unsigned m  = 0x7fffffff;
    unsigned k1 = 2*floor(m*(.5 - sqrt(3)/6.)) + 1;
    unsigned k2 = 8*ceil(m*atan(1.)/8.) + 5;
Calculating that square root and that inverse tangent is computationally costly, and it is best to calculate them in advance. Especially since k1 and k2 are used in a linear congruential pseudorandom-number generator:
Code:
    rand_num = rand_num*k2 + k1;
 Linear congruential generator

 List of random number generators - lots of them have been devised, though strictly speaking, many of them generate pseudoranndom numbers.
 
I coded it from FORTRAN from the 70s paper. URAND A Universal Random Number Generator, its on the net.

For a given m K1 and K2 are constants that can be precalculated, I showed it as it is in the paper for clarity. Each iteration then is a multiplication and an addition.

In the days of multiple systems with nonstandard number sizes m represents the word size for the platform. In this case it is a 32 bit int. For a 64 bit int m would change.

What I like about the C function I coded is that it is simple, self contained, and portable. It It peroxides a 30 bit integer random number as compared to the rand() 15 bits.

The native C++ random functions are good, but simplicity is lost with multiple generators.

If I were coding some work related math analysis today I'd use C++ and the random functions.

I think the optimized Intel math library comes with the MS C++ distribution.
 
Back
Top Bottom