2. Numbers

Checking Whether a String Is a Valid Number

string number="123.3asdf";

int|float realnumber= (int)number;  // casting to int will throw away all

                                    // nonnumber parts

string rest;
[realnumber, rest] = array_sscanf(number, "%d%s"); // scan for an integer

// if rest contains anything but the empty string, then there was more than a

// number in the string

// use %f to scan for float, %x for hex or %o for octal

Comparing Floating-Point Numbers

int same(float one, float two, int accuracy)
{
  return sprintf("%.*f", accuracy, one) == sprintf("%.*f", accuracy, two);
}

int wage=536;
int week=40*wage;
write("one week's wage is: $%.2f\n", week/100.0);

Rounding Floating-Point Numbers

float unrounded=3.5;
string rounded=sprintf("%.*f", accuracy, unrounded);

float a=0.255;
string b=sprintf("%.2f", a);

write("Unrounded: %f\nRounded: %s\n", a, b);
write("Unrounded: %f\nRounded: %.2f\n", a, a);

// dec to bin

string bin=sprintf("%b", 5);

int dec=array_sscanf("0000011111111111111", "%b")[0]; 
                // array_sscanf returns an array


int num = array_sscanf("0110110", "%b")[0];  // num is 54

string binstr = sprintf("%b", 54);           // binstr is 110110


Converting Between Binary and Decimal

// contributed by martin nilsson.


string dec2bin(int n) 
{ 
  return sprintf("%b",n); 
}

int bin2dec(string n) 
{ 
  return array_sscanf(n, "%b")[0];
}

Operating on a Series of Integers

// foreach(enumerate(int count, int step, int start);; int val)

// {

//   // val is set to each of count integers starting at start

// }


foreach(enumerate(y-x+1,1,x);; int val)
{
  // val is set to every integer from X to Y, inclusive

}

for(int i=x; i<=y; i++)
{
  // val is set to every integer from X to Y, inclusive

}

for(int i=x; i<=y; i+=7)
{
  // val is set to every integer from X to Y, stepsize = 7

}

foreach(enumerate(y-x+1,7,x);; int val)
{
  // val is set to every integer from X to Y, stepsize = 7

}

//----------------------------------------

write("Infancy is: ");
foreach(enumerate(3);; int val) 
{
  write("%d ", val);
}
write("\n");

write("Toddling is: %{%d %}\n", enumerate(2,1,3));

write("Childhood is: ");
for (int i = 5; i <= 12; i++) 
{
  write("%d ", i);
}
write("\n");

// Infancy is: 0 1 2 

// Toddling is: 3 4 

// Childhood is: 5 6 7 8 9 10 11 12 

Working with Roman Numerals

int arabic;
string roman = String.int2roman(arabic);        // handles values up to 10000


array nums=enumerate(10001);                
array romans=String.int2roman(nums[*]);     
mapping roman2int = mkmapping(romans, nums);                   

int arabic = roman2int[roman];

//------------------------------------------------

string roman_fifteen = String.int2roman(15);    //  "XV"

write("Roman for fifteen is %s\n", roman_fifteen);

int arabic_fifteen = roman2int[roman_fifteen];
write("Converted back, %s is %d\n", roman_fifteen, arabic_fifteen);

// Roman for fifteen is XV

// Converted back, XV is 15

Generating Random Numbers

int y,x;
int rand = random(y-x+1)+x;

float y,x;
float rand = random(y-x+1)+x;

int rand = random(51)+25;
write("%d\n", rand);

array arr;
mixed elt = arr[random(sizeof(arr))];
mixed elt = random(arr);

array chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@$%^&*"/"";
string password = "";
for(int i=1; i<=8; i++)
{
  password+=random(chars);
}

string password = random((({chars})*8)[*])*"";

string password = random_string(8);      // creates an untypable string


// turn the string into something typable using the base64 charset

string password = MIME.encode_base64(random_string(8))[..7];

Generating Different Random Numbers

random_seed(int seed);
random_seed((int)argv[1]);

Making Numbers Even More Random

// Crypto.Random.random(int max)

// Crypto.Random.random_string(int length)

// Crypto.Random.blocking_random_string(int length)

// Crypto.Random.add_entropy(string random_data, int entropy)

Generating Biased Random Numbers

float gaussian_rand()
{
  float u1, u2, w, g1, g2;
  
  do
  {
    u1 = 2.0 * random(1.0) - 1.0; u2 = 2.0 * random(1.0) - 1.0;
    w = u1 * u1 + u2 * u2;
  } while (w > 1.0);
  
  w = sqrt((-2.0 * log(w)) / w); g2 = u1 * w; g1 = u2 * w;

  return g1;
}

// ----


float mean = 25.0, sdev = 2.0;
float salary = gaussian_rand() * mean + sdev;

write("You have been hired at: %.2f\n", salary);

Doing Trigonometry in Degrees, not Radians

float deg2rad(float deg)
{
  return (deg / 180.0) * Math.pi;
}

float rad2deg(float rad)
{
  return (rad / Math.pi) * 180.0;
}

// ----


write("%f\n", Math.convert_angle(180, "deg", "rad"));
write("%f\n", deg2rad(180.0));

// ----------------------------


float degree_sin(float deg)
{
  return sin(deg2rad(deg));
}

// ----


float rad = deg2rad(380.0);
write("%f\n", sin(rad));
write("%f\n", degree_sin(380.0));

Calculating More Trigonometric Functions

float my_tan(float theta)
{
  return sin(theta) / cos(theta);
}

// ----


float theta = 3.7;

write("%f\n", my_tan(theta));
write("%f\n", tan(theta));

Taking Logarithms

float value = 100.0;

float log_e = log(value);
float log_10 = Math.log10(value);

// ----------------------------


float log_base(float base, float value)
{
  return log(value) / log(base);
}

// ----


float answer = log_base(10.0, 10000.0);

write("log(10, 10,000) = %f\n", answer);

Multiplying Matrices

// Pike offers a solid matrix implementation; highlights:

// * Operator overloading makes matrix operations succinct

// * Matrices may be of various types, thus allowing user to

//   choose between range representation and speed

// * Wide variety of operations available


Math.Matrix a = Math.Matrix( ({ ({3, 2, 3}), ({5, 9, 8})  }) ),
            b = Math.Matrix( ({ ({4, 7}), ({9, 3}), ({8, 1}) }) );

Math.Matrix c = a * b;

// ------------


Math.Matrix t = c->transpose();

Using Complex Numbers

// @@INCOMPLETE@@

Converting Between Octal and Hexadecimal

// Like C, Pike supports decimal-alternate notations. Thus, for example,

// the integer value, 867, is expressable in literal form as:

//

//   Hexadecimal -> 0x363

//   Octal       -> 01543

//

// For effecting such conversions using strings there is 'sprintf' and

// 'sscanf'.


int dec = 867;
string hex = sprintf("%x", dec);
string oct = sprintf("%o", dec);

// ------------


int dec;
string hex = "363"; sscanf(hex, "%x", dec);

// ------------


int dec;
string oct = "1543"; sscanf(oct, "%o", dec);

// ----------------------------


int number;

write("Gimme a number in decimal, octal, or hex: ");
sscanf(Stdio.stdin->gets(), "%D", number);

write("%d %x %o\n", number, number, number);

Putting Commas in Numbers

string commify_series(int series)
{
  return reverse((reverse((string)series) / 3.0) * ",");
}

// ----


int hits = 3452347;

write("Your website received %s accesses last month.\n", commify_series(hits));

// ----------------------------


string commify(string s)
{
  function t = lambda(string m) { return reverse((reverse(m) / 3.0) * ","); };
  return Regexp.PCRE("([0-9]+)")->replace(s, t);
}

// ----


int hits = 3452347;
string output = sprintf("Your website received %d accesses last month.", hits);

write("%s\n", commify(output));

Printing Correct Plurals

string pluralise(int value, string root, void|string singular_, void|string plural_)
{
  string singular = singular_ ? singular_ : "";
  string plural = plural_ ? plural_ : "s";

  return root + ( (value > 1) ? plural : singular );
}

// ----


int duration = 1;
write("It took %d %s\n", duration, pluralise(duration, "hour"));
write("%d %s %s enough.\n", duration, pluralise(duration, "hour"),
      pluralise(duration, "", "is", "are"));

duration = 5;
write("It took %d %s\n", duration, pluralise(duration, "hour"));
write("%d %s %s enough.\n", duration, pluralise(duration, "hour"),
      pluralise(duration, "", "is", "are"));

// ----------------------------


// Non-regexp implementation, uses the string-based, 'has_prefix'

// and 'replace' library functions

string plural(string singular)
{
  mapping(string : string) e2 =
    (["ss":"sses", "ph":"phes", "sh":"shes", "ch":"ches",
      "ey":"eys", "ix":"ices", "ff":"ffs"]);

  mapping(string : string) e1 =
    (["z":"zes", "f":"ves", "y":"ies", "s":"ses", "x":"xes"]);

  foreach(({e2, e1}), mapping(string : string) endings) 
  {
    foreach(indices(endings), string ending)
    {
      if (has_suffix(singular, ending))
      {
        return replace(singular, ending, endings[ending]);
      }
    }
  }

  return singular;
}

// ----


int main()
{
  foreach(aggregate("mess", "index", "leaf", "puppy"), string word)
    write("%6s -> %s\n", word, plural(word));
}

Program: Calculating Prime Factors

// download the following standalone program
#!/usr/bin/pike
// contributed by martin nilsson

void main(int n, array args) 
{
  foreach(args[1..], string arg) 
  {
    mapping r = ([]);
    foreach(Math.factor((int)arg), int f)
      r[f]++;
    write("%-10s", arg);
    if(sizeof(r)==1)
      write(" PRIME");
    else 
    {
      foreach(sort(indices(r)), int f) 
      {
        write(" %d", f);
        if(r[f]>1) write("**%d", r[f]);
      }
    }
    write("\n");
  }
}