function displaynumber (s)
  {
    var precision    = document.getElementById ('precision').value;
    var threshold    = document.getElementById ('threshold').value;
    if (s > Math.pow (10, threshold) || s < Math.pow (10, -threshold))
      {
        s = s.toExponential (precision);
      }
    
    if (document.getElementById ('commas').checked)
      {
        s += '';
        x = s.split('.');
        x1 = x[0];
        x2 = x.length > 1 ? '.' + x[1] : '';
        var rgx = /(\d+)(\d{3})/;
        while (rgx.test (x1))
          {
            x1 = x1.replace (rgx, '$1' + ',' + '$2');
          }
        return x1 + x2;
      }
    else
      {
        return s;
      }
  }

function getrawnumber (s)
  {
    n = s.replace (/,/g, '');
    return n.replace (/^([+-]?\d*.?\d*)e([+-]?\d+)$/i, function (f, n, e) { return n * Math.pow (10, e);});
  }
  
function ExtendedMath ()
  {
    // Some basic constants
    this.c      = 299792458; // Speed of light in meters per second
    this.u0     = 0.00000125663706; // Pemeability of free space
    this.stefan = 0.000000056704; // Stefan-Boltzmanm constant
    // masses
    this.mass_proton = 0.00000000000000000000000000167262171;
    // The hyperbolic trig functions are required for the relativistic acceleration calculation methods.
    this.cosh = function (x) { return (Math.exp (x) + Math.exp (-x)) / 2; };
    this.arcosh = function (x) { return Math.log (x + Math.sqrt (x - 1) * Math.sqrt (x + 1)); };
    this.sinh = function (x) { return (Math.exp (x) - Math.exp (-x)) / 2; };
    this.arsinh = function (x) { return Math.log (x + Math.sqrt (x * x + 1)); };
    this.tanh = function (x) { return (Math.exp (2 * x) - 1) / (Math.exp (2 * x) + 1); };
    this.artanh = function (x) { return .5 * Math.log ((1 + x)/(1 - x)); };
    // mag for Magnetic functions.
    // MPF - Maxwell's Pulling Force formula.
    this.magMPF = function (a, b) { return a * b * b / (2 * this.u0); };
    this.tempFromAE = function (a, e) { return Math.sqrt (Math.sqrt (e / (0.000000056704 * a))); };
    // rel is for Relativistic functions, performing basic transformations and such.
    // G - Gamma or Lorentz factor.
    // RM - Relativistic Mass in kilograms
    // IM - Invariant Mass in kilograms
    // RFT - Rest Frame Time in seconds
    // AFT - Accelerating Frame Time in seconds
    // D - Rest Frame Distance in meters
    // V - Velocity in meters per second.
    // E - Energy in joules
    // Mom - Relativistic Momentum in Newton seconds
    this.relGFromV     = function (v) { return 1 / Math.sqrt (1 - (v / this.c) * (v / this.c)); };
    this.relVFromG     = function (g) { return this.c * Math.sqrt (1 - 1 / (g * g)); };
    this.relEFromIMG   = function (m, g) { return m * g * this.c * this.c - m * this.c * this.c; };
    this.relRMFromIMG  = function (m, g) { return m * g; };
    this.relMomFromIMV = function (m, v) { return m * this.relGFromV (v) * v; };
    // The first parameter to these methods is always acceleration.
    // The following functions were taken from the following url:
    // http://www.math.ucr.edu/home/baez/physics/Relativity/SR/rocket.html
    this.relRFTFromD   = function (a, d) { return Math.sqrt ((d / this.c) * (d / this.c) + 2 * d / a); };
    this.relRFTFromAFT = function (a, T) { return (this.c / a) * this.sinh (a * T / this.c); };
    this.relAFTFromD   = function (a, d) { return (this.c / a) * this.arcosh (a * d / (this.c * this.c) + 1); };
    this.relAFTFromRFT = function (a, t) { return (this.c / a) * this.arsinh (a * t / this.c); };
    this.relDFromRFT   = function (a, t) { return (this.c * this.c / a) * (Math.sqrt (1 + (a * t / this.c) * (a * t / this.c)) - 1); };
    this.relDFromAFT   = function (a, T) { return (this.c * this.c / a) * (this.cosh (a * T / this.c) - 1); };
    this.relVFromRFT   = function (a, t) { var at = a * t; return at / Math.sqrt (1 + (at / this.c) * (at / this.c)); };
    this.relVFromAFT   = function (a, T) { return this.c * this.tanh (a * T / this.c); };
    // Inverse function to calculate from a desired velocity. More would be useful but aren't required.
    this.relRFTfromV   = function (a, v) { return Math.sqrt (1 / ((a * a) / (v * v) - (a * a) / (this.c * this.c))); };
    this.relAFTfromV   = function (a, v) { return (this.c / a) * artanh (v / this.c); };
  }
  
  ExMath = new ExtendedMath ();
  
function calc_acceleration ()
  {
    var field    = getrawnumber (document.getElementById ('field').value);
    var area     = getrawnumber (document.getElementById ('area').value);
    var length   = getrawnumber (document.getElementById ('length').value);
    var density  = getrawnumber (document.getElementById ('density').value);
    var mass     = area * length * 1000 * density;
    var force    = ExMath.magMPF (area, field);
    document.getElementById ('force').innerHTML = displaynumber (force);
    document.getElementById ('mass').value = displaynumber (mass);
    document.getElementById ('acceleration').innerHTML = displaynumber (force / mass);
    
    document.getElementById ('field').value = displaynumber (field);
    document.getElementById ('area').value = displaynumber (area);
    document.getElementById ('length').value = displaynumber (length);
    document.getElementById ('density').value = displaynumber (density);
    calc_from_distance ();
  }
  
function calc_from_mass ()
  {
    var field    = getrawnumber (document.getElementById ('field').value);
    var area     = getrawnumber (document.getElementById ('area').value);
    var length   = getrawnumber (document.getElementById ('length').value);
    var density  = getrawnumber (document.getElementById ('density').value);
    var mass     = getrawnumber (document.getElementById ('mass').value);
    var force    = ExMath.magMPF (area, field);
    document.getElementById ('force').innerHTML = displaynumber (force);
    document.getElementById ('length').value = displaynumber (mass / (area * density * 1000));
    document.getElementById ('acceleration').innerHTML = displaynumber (force / mass);
    calc_from_distance ();
  }

function calc_from_distance ()
  {
    var distance     = getrawnumber (document.getElementById ('distance').value) * 1000;
    var acceleration = getrawnumber (document.getElementById ('acceleration').innerHTML);
    var time = ExMath.relRFTFromD (acceleration, distance); 
    document.getElementById ('time').value = displaynumber (time);
    var velocity = ExMath.relVFromRFT (acceleration, time); 
    document.getElementById ('distancely').value = displaynumber (distance / 9460528400000000);
    document.getElementById ('velocity').value = displaynumber (velocity);
    document.getElementById ('cvelocity').value = displaynumber (velocity / 299792458);
    document.getElementById ('contraction').value = displaynumber (ExMath.relGFromV (velocity));
    calc_derived ();
  }
  
function calc_from_distancely ()
  {
    var distance     = getrawnumber (document.getElementById ('distancely').value) * 9460528400000000;
    document.getElementById ('distance').value = displaynumber (distance / 1000);
    calc_from_distance ();
  }

function calc_from_time ()
  {
    var time         = getrawnumber (document.getElementById ('time').value);
    var acceleration = getrawnumber (document.getElementById ('acceleration').innerHTML);
    var distance = ExMath.relDFromRFT (acceleration, time);
    var velocity = ExMath.relVFromRFT (acceleration, time); 
    document.getElementById ('distance').value = displaynumber (distance / 1000);
    document.getElementById ('distancely').value = displaynumber (distance / 9460528400000000);
    document.getElementById ('velocity').value = displaynumber (velocity);
    document.getElementById ('contraction').value = displaynumber (ExMath.relGFromV (velocity));
    calc_derived ();
  }
  
function calc_from_velocity ()
  {
    var acceleration = getrawnumber (document.getElementById ('acceleration').innerHTML);
    var velocity     = getrawnumber (document.getElementById ('velocity').value);
    if (velocity > ExMath.c)
      {
        velocity = ExMath.c;
        document.getElementById ('velocity').value = displaynumber (ExMath.c);
      }
    var time = ExMath.relRFTfromV (acceleration, velocity);
    document.getElementById ('time').value = displaynumber (time);
    var distance = ExMath.relDFromRFT (acceleration, time);
    document.getElementById ('distance').value = displaynumber (distance / 1000);
    document.getElementById ('distancely').value = displaynumber (distance / 9460528400000000);
    document.getElementById ('contraction').value = displaynumber (ExMath.relGFromV (velocity));
    calc_derived ();
  }
  
function calc_from_fractionc ()
  {
    var cvelocity    = getrawnumber (document.getElementById ('cvelocity').value);
    var acceleration = getrawnumber (document.getElementById ('acceleration').innerHTML);
    if (cvelocity > 1.0)
      {
        cvelocity = 1.0;
      }
    else if (cvelocity < 0)
      {
        cvelocity = 0;
      }
    document.getElementById ('cvelocity').value = displaynumber (cvelocity);
    var velocity = cvelocity * ExMath.c;
    document.getElementById ('velocity').value = displaynumber (velocity);
    var time = ExMath.relRFTfromV (acceleration, velocity);
    document.getElementById ('time').value = displaynumber (time);
    var distance = ExMath.relDFromRFT (acceleration, time);
    document.getElementById ('distance').value = displaynumber (distance / 1000);
    document.getElementById ('distancely').value = displaynumber (distance / 9460528400000000);
    document.getElementById ('contraction').value = displaynumber (ExMath.relGFromV (velocity));
    calc_derived ();
  }
  
function calc_from_contraction ()
  {
    var contraction = getrawnumber (document.getElementById ('contraction').value);
    var acceleration = getrawnumber (document.getElementById ('acceleration').innerHTML);
    var velocity = ExMath.relVFromG (contraction); //c * Math.sqrt (1 - 1 / (contraction * contraction));
    document.getElementById ('velocity').value = displaynumber (velocity);
    var time = ExMath.relRFTfromV (acceleration, velocity);
    document.getElementById ('time').value = displaynumber (time);
    var distance = ExMath.relDFromRFT (acceleration, time);
    document.getElementById ('distancely').value = displaynumber (distance / 9460528400000000);
    document.getElementById ('distance').value = displaynumber (distance / 1000);
    calc_derived ();
  }
  
function calc_derived ()
  {
    var time         = getrawnumber (document.getElementById ('time').value);
    var acceleration = getrawnumber (document.getElementById ('acceleration').innerHTML);
    var distance     = getrawnumber (document.getElementById ('distance').value) * 1000;
    var mass         = getrawnumber (document.getElementById ('mass').value);
    var velocity     = getrawnumber (document.getElementById ('velocity').value);
    var cvelocity    = getrawnumber (document.getElementById ('cvelocity').value);
    var contraction  = getrawnumber (document.getElementById ('contraction').value);
    var efficiency   = getrawnumber (document.getElementById ('efficiency').value);
    if (efficiency > 100.0)
      {
        efficiency = 100.0;
        document.getElementById ('efficiency').value = 100.0;
      }
    if (efficiency < 0.0001)
      {
        efficiency = 0.0001;
        document.getElementById ('efficiency').value = 0.0001;
      }
    efficiency /= 100.0;
    var projectileshare = getrawnumber (document.getElementById ('projectileshare').value);
    if (projectileshare > 100.0)
      {
        projectileshare = 100.0;
        document.getElementById ('projectileshare').value = 100.0;
      }
    if (projectileshare < 0.0000000001)
      {
        projectileshare = 0.0000000001;
        document.getElementById ('projectileshare').value = 0.0000000001;
      }
    projectileshare /= 100.0;
    var energy         = ExMath.relEFromIMG (mass, contraction); //mass * contraction * c * c - mass * c * c;
    var projectiletime = ExMath.relAFTFromRFT (acceleration, time); //(c / acceleration) * ExMath.arsinh (acceleration * time / c);
    var velocity2 = 0;
    var contraction2 = 1;
    var energy2 = energy / time;

    velocity2 = ExMath.relVFromRFT (acceleration, time * .999);
    contraction2 = ExMath.relGFromV (velocity2);
    energy2 = energy - ExMath.relEFromIMG (mass, contraction2);

    var projectileaverageenergy = energy / (projectiletime * efficiency * 1000000);
    var peakenergy = energy2 / (time * efficiency * 1000);
    document.getElementById ('projectiletime').innerHTML = displaynumber (projectiletime);
    document.getElementById ('energy').innerHTML = displaynumber (energy / 1000000000);
    document.getElementById ('energytnt').innerHTML = displaynumber (energy / 4184000000);
    document.getElementById ('averageenergy').innerHTML = displaynumber (energy / (time * efficiency * 1000000));
    //document.getElementById ('projectileaverageenergy').innerHTML = displaynumber (projectileaverageenergy);
    document.getElementById ('peakenergy').innerHTML = displaynumber (peakenergy);
    //document.getElementById ('projectilepeakenergy').innerHTML = displaynumber (peakenergy * contraction);
    document.getElementById ('heatabsorb').innerHTML = displaynumber (projectileaverageenergy * (1.0 - efficiency) * projectileshare);
    document.getElementById ('peakabsorb').innerHTML = displaynumber (peakenergy * contraction * (1.0 - efficiency) * projectileshare);
    document.getElementById ('relmass').innerHTML = displaynumber (contraction * mass);
    document.getElementById ('momentum').innerHTML = displaynumber (contraction * mass * velocity);
    calc_ism ();
  }

function calc_ism ()
  {
    var area        = getrawnumber (document.getElementById ('area').value);
    var mass        = getrawnumber (document.getElementById ('mass').value);
    var medium      = getrawnumber (document.getElementById ('medium').value);
    var contraction = getrawnumber (document.getElementById ('contraction').value);
    var velocity    = getrawnumber (document.getElementById ('velocity').value);
    var targetly    = getrawnumber (document.getElementById ('targetly').value);
    var matter      = area * 10000 * medium * targetly * 946052840000000000 * 1.3 * 1000 * ExMath.mass_proton;
    document.getElementById ('matter').innerHTML = displaynumber (matter);
    document.getElementById ('massratio').innerHTML = displaynumber (matter / (mass * 10));
    var impactrate  = area * medium * velocity * contraction * 1000000;
    document.getElementById ('impactrate').innerHTML = displaynumber (impactrate);
    var impactratemass = impactrate * 1.3 * ExMath.mass_proton;
    document.getElementById ('impactratemass').innerHTML = displaynumber (impactratemass * 1000);
    var impactenergy = ExMath.relEFromIMG (impactratemass, contraction);
    document.getElementById ('impactenergy').innerHTML = displaynumber (impactenergy);
    var temperature = ExMath.tempFromAE (area, impactenergy);
    document.getElementById ('temperature').innerHTML = displaynumber (temperature);
  }

