What is the actual mathematical expression for Google Mercator? Confirm it through Safari's Web Inspector on OpenLayers and Proj4js

Thanks to http://www.spatialreference.org/ , it is very easy to check the WKT definitions for WGS84 and "Google Mercator" projection. But the actual mathematical expression to convert Google Mercator to WGS84 is not so easy to check, although the expression is published at http://en.wikipedia.org/wiki/Mercator_projection#Mathematics_of_the_projection . This entry shows how we can check the expression on existing JavaScript code using Web Inspector of Safari or Chrome.
This is the English version of http://d.hatena.ne.jp/hfu/20100906/1283778909 .

The method

"Console" is a nice tool in Web Inspector accompanied with Safari or Chrome. We can access any JavaScript object loaded on the page by typing JavaScript code snippet. We can easily understand the object and the code like we can in Ruby using 'irb.'

The case for OpenLayers

http://trac.openlayers.org/wiki/SphericalMercator indicates that OpenLayers.Layer.SphericalMercator.projectInverse is the actual function for inverse-transform from Google Mercator to WGS84. Using Console, another function is revealed to handle it:

> OpenLayers.Layer.SphericalMercator.projectInverse
function (point) {var lonlat=OpenLayers.Layer.SphericalMercator.inverseMercator(point.x,point.y);point.x=lonlat.lon;point.y=lonlat.lat;return point;}
> OpenLayers.Layer.SphericalMercator.inverseMercator
function (x, y) {var lon=(x/20037508.34)*180;var lat=(y/20037508.34)*180;lat=180/Math.PI*(2*Math.atan(Math.exp(lat*Math.PI/180))-Math.PI/2);return new OpenLayers.LonLat(lon,lat);}

This expression seems to be a plain implementation of http://en.wikipedia.org/wiki/Mercator_projection#Mathematics_of_the_projection .
On the other hand, the forward-transform is;

> OpenLayers.Layer.SphericalMercator.projectForward
function (point) {var lonlat=OpenLayers.Layer.SphericalMercator.forwardMercator(point.x,point.y);point.x=lonlat.lon;point.y=lonlat.lat;return point;}
> OpenLayers.Layer.SphericalMercator.forwardMercator
function (lon, lat) {var x=lon*20037508.34/180;var y=Math.log(Math.tan((90+lat)*Math.PI/360))/(Math.PI/180);y=y*20037508.34/180;return new OpenLayers.LonLat(x,y);}

This seems also to be a plain implementation of http://en.wikipedia.org/wiki/Mercator_projection#Mathematics_of_the_projection .

Numerical experiment
> var m = OpenLayers.Layer.SphericalMercator
undefined
> var mp = m.forwardMercator(135, 35)
undefined
> mp.toString()
"lon=15028131.255,lat=4163881.1434847"
> m.inverseMercator(mp.lon, mp.lat).toString()
"lon=135,lat=35"

OK, inverse transform after forward transform is confirmed to be identity.

Proj4js

I also checked Proj4js using Web Inspector of Safari, too.
Some information taken from; http://trac.osgeo.org/proj4js/wiki/UserGuide#Basics
The page at which I run Web Inspector: http://proj4js.org/

> Proj4js.transform
function (source, dest, point) {
        if (!source.readyToUse || !dest.readyToUse) {
            this.reportError("Proj4js initialization for "+source.srsCode+" not yet complete");
            return point;
        }
        
        // Workaround for Spherical Mercator
        if ((source.srsProjNumber =="900913" && dest.datumCode != "WGS84") ||
            (dest.srsProjNumber == "900913" && source.datumCode != "WGS84")) {
            var wgs84 = Proj4js.WGS84;
            this.transform(source, wgs84, point);
            source = wgs84;
        }

        // Transform source points to long/lat, if they aren't already.
        if ( source.projName=="longlat") {
            point.x *= Proj4js.common.D2R;  // convert degrees to radians
            point.y *= Proj4js.common.D2R;
        } else {
            if (source.to_meter) {
                point.x *= source.to_meter;
                point.y *= source.to_meter;
            }
            source.inverse(point); // Convert Cartesian to longlat
        }

        // Adjust for the prime meridian if necessary
        if (source.from_greenwich) { 
            point.x += source.from_greenwich; 
        }

        // Convert datums if needed, and if possible.
        point = this.datum_transform( source.datum, dest.datum, point );

        // Adjust for the prime meridian if necessary
        if (dest.from_greenwich) {
            point.x -= dest.from_greenwich;
        }

        if( dest.projName=="longlat" ) {             
            // convert radians to decimal degrees
            point.x *= Proj4js.common.R2D;
            point.y *= Proj4js.common.R2D;
        } else  {               // else project
            dest.forward(point);
            if (dest.to_meter) {
                point.x /= dest.to_meter;
                point.y /= dest.to_meter;
            }
        }
        return point;
    }
> new Proj4js.Proj('EPSG:900913').inverse(new Proj4js.Point(15028131.255, 4163881.1434847)).toString()
"x=2.35619448986436,y=0.6108652381235775"
> new Proj4js.Proj('EPSG:900913').inverse(new Proj4js.Point(15028131.255, 4163881.1434847)).x
2.35619448986436
> new Proj4js.Proj('EPSG:900913').inverse(new Proj4js.Point(15028131.255, 4163881.1434847)).x * Proj4js.common.R2D
134.99999998120785

The coordinates forward transformed using OpenLayers came back to almost the same coordinates via inverse transform using Proj4js. (The slight difference might be from the string conversion of floating point numbers.) The actual inverse transform expression was like the following;

> new Proj4js.Proj('EPSG:900913').inverse
function (p) {	

    var x = p.x - this.x0;
    var y = p.y - this.y0;
    var lon,lat;

    if (this.sphere) {
      lat = Proj4js.common.HALF_PI - 2.0 * Math.atan(Math.exp(-y / this.a * this.k0));
    } else {
      var ts = Math.exp(-y / (this.a * this.k0));
      lat = Proj4js.common.phi2z(this.e,ts);
      if(lat == -9999) {
        Proj4js.reportError("merc:inverse: lat = -9999");
        return null;
      }
    }
    lon = Proj4js.common.adjust_lon(this.long0+ x / (this.a * this.k0));

    p.x = lon;
    p.y = lat;
    return p;
  }