Index: lucene/core/src/java/org/apache/lucene/util/SloppyMath.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/util/SloppyMath.java	(revision 1542802)
+++ lucene/core/src/java/org/apache/lucene/util/SloppyMath.java	(working copy)
@@ -46,7 +46,13 @@
     double h1 = (1 - cos(x1 - x2)) / 2;
     double h2 = (1 - cos((lon1 - lon2) * TO_RADIANS)) / 2;
     double h = h1 + cos(x1) * cos(x2) * h2;
-    return TO_KILOMETERS * 2 * asin(Math.min(1, Math.sqrt(h)));
+
+    double avgLat = Math.abs((x1 + x2) / 2d);
+    int index = (int)(avgLat * RADIUS_INDEXER + 0.5);
+    double radius = earthRadiusPerLatitude[index];
+
+    return radius * 2 * asin(Math.min(1, Math.sqrt(h)));
+    
   }
 
   /**
@@ -133,7 +139,6 @@
   
   // haversin
   private static final double TO_RADIANS = Math.PI / 180D;
-  private static final double TO_KILOMETERS = 6371.0087714D;
   
   // cos/asin
   private static final double ONE_DIV_F2 = 1/2.0;
@@ -183,6 +188,11 @@
   private static final double ASIN_QS3 = Double.longBitsToDouble(0xbfe6066c1b8d0159L); // -6.88283971605453293030e-01
   private static final double ASIN_QS4 = Double.longBitsToDouble(0x3fb3b8c5b12e9282L); //  7.70381505559019352791e-02
   
+  private static final int RADIUS_TABS_SIZE = (1<<10) + 1;
+  private static final double RADIUS_DELTA = (StrictMath.PI/2d) / (RADIUS_TABS_SIZE - 1);
+  private static final double RADIUS_INDEXER = 1d/RADIUS_DELTA;
+  private static final double[] earthRadiusPerLatitude = new double[RADIUS_TABS_SIZE];
+  
   /** Initializes look-up tables. */
   static {
     // sin and cos
@@ -225,5 +235,27 @@
       asinDer3DivF3Tab[i] = ((1+2*x*x)*oneMinusXSqInv2_5) * ONE_DIV_F3;
       asinDer4DivF4Tab[i] = ((5+2*x*(2+x*(5-2*x)))*oneMinusXSqInv3_5) * ONE_DIV_F4;
     }
+    
+    
+    // WGS84 earth-ellipsoid major (a) and minor (b) radius
+    final double a = 6_378_137; // [m]
+    final double b = 6_356_752.31420; // [m]
+    
+    final double a2 = a*a;
+    final double b2 = b*b;
+    
+    earthRadiusPerLatitude[0] = a / 1000d;
+    earthRadiusPerLatitude[RADIUS_TABS_SIZE-1] = b / 1000d;
+    // earth radius
+    for (int i=1;i<RADIUS_TABS_SIZE-1;i++) {
+      final double lat = Math.PI * i / (2d * RADIUS_TABS_SIZE-1);
+      double one = StrictMath.pow(a2 * StrictMath.cos(lat), 2); 
+      double two = StrictMath.pow(b2 * StrictMath.sin(lat), 2);
+      double three = StrictMath.pow(a * StrictMath.cos(lat), 2);
+      double four = StrictMath.pow(b * StrictMath.sin(lat), 2);
+      
+      double radius = StrictMath.sqrt((one+two)/(three+four));
+      earthRadiusPerLatitude[i] = radius / 1000d;
+    }
   }
 }
Index: lucene/core/src/test/org/apache/lucene/util/TestSloppyMath.java
===================================================================
--- lucene/core/src/test/org/apache/lucene/util/TestSloppyMath.java	(revision 1542802)
+++ lucene/core/src/test/org/apache/lucene/util/TestSloppyMath.java	(working copy)
@@ -93,8 +93,12 @@
     assertEquals(0, haversin(90, -180, 90, 180), 0D);
     assertEquals(0, haversin(90, 180, 90, 180), 0D);
     
+    // Test half a circle on the equator, using WGS84 earth radius
+    double earthRadiusKMs = 6378.137;
+    double halfCircle = earthRadiusKMs * Math.PI;
+    assertEquals(halfCircle, haversin(0, 0, 0, 180), 0D);
+
     // from solr and ES tests (with their respective epsilons)
-    assertEquals(314.40338, haversin(1, 2, 3, 4), 10e-5);
     assertEquals(0, haversin(40.7143528, -74.0059731, 40.7143528, -74.0059731), 0D);
     assertEquals(5.286, haversin(40.7143528, -74.0059731, 40.759011, -73.9844722), 0.01D);
     assertEquals(0.4621, haversin(40.7143528, -74.0059731, 40.718266, -74.007819), 0.01D);
Index: lucene/expressions/src/test/org/apache/lucene/expressions/TestDemoExpressions.java
===================================================================
--- lucene/expressions/src/test/org/apache/lucene/expressions/TestDemoExpressions.java	(revision 1542802)
+++ lucene/expressions/src/test/org/apache/lucene/expressions/TestDemoExpressions.java	(working copy)
@@ -198,12 +198,12 @@
     TopFieldDocs td = searcher.search(new MatchAllDocsQuery(), null, 3, sort);
     
     FieldDoc d = (FieldDoc) td.scoreDocs[0];
-    assertEquals(0.4621D, (Double)d.fields[0], 1E-4);
+    assertEquals(0.4619D, (Double)d.fields[0], 1E-4);
     
     d = (FieldDoc) td.scoreDocs[1];
-    assertEquals(1.0550D, (Double)d.fields[0], 1E-4);
+    assertEquals(1.0546D, (Double)d.fields[0], 1E-4);
     
     d = (FieldDoc) td.scoreDocs[2];
-    assertEquals(5.2859D, (Double)d.fields[0], 1E-4);
+    assertEquals(5.2842D, (Double)d.fields[0], 1E-4);
   }
 }
Index: lucene/expressions/src/test/org/apache/lucene/expressions/js/TestJavascriptFunction.java
===================================================================
--- lucene/expressions/src/test/org/apache/lucene/expressions/js/TestJavascriptFunction.java	(revision 1542802)
+++ lucene/expressions/src/test/org/apache/lucene/expressions/js/TestJavascriptFunction.java	(working copy)
@@ -158,7 +158,7 @@
   }
   
   public void testHaversinMethod() throws Exception {
-    assertEvaluatesTo("haversin(40.7143528,-74.0059731,40.759011,-73.9844722)", 5.285885589128);
+    assertEvaluatesTo("haversin(40.7143528,-74.0059731,40.759011,-73.9844722)", 5.284299568309);
   }
   
   public void testLnMethod() throws Exception {
