Convert Units Of Distance (Miles, Meters, Kilometer), Rounding Issues

Not sure if it is the conversion formulas, rounding formula or just logic. But on the sample below, select "marathon" and I am using 42195 meters as seen in the html code.  This gets converted to kilometers 42.197 which seems odd.  then use then use the drop down to change from kilometers, to miles, to meters and back to kilometers and the number is not the same in the text box. It is now 42.199

http://jsbin.com/codowocore/edit?html,js,output
JQUERY
$(function() {
  
  // select length of run
    var currentMeasure = $('select#distanceUnit option:selected').text(); // current distance unit (miles, meters)
    $('#distanceSelect').on('change', function() { // get the distance from drop down
        var distanceSelect = $('#distanceSelect').val();
        var convertTo = $('select#distanceUnit option:selected').text(); // convert from meters or what is currently selected to new measure
        if (distanceSelect !== '') {
// convert distance to selected distance unit
            var c = convert('Meter', convertTo, distanceSelect);
// place converted lenght in text box
            $('#distance').val(c);
        }

    });

  // recalculate the distance measure if change unit of measure
    $('#distanceUnit').on('change', function() {

        var currentDistance = $('#distance').val();
        var newMeasure = $(this).val();

        var newDistance = convert(currentMeasure, newMeasure, currentDistance);

        $('#distance').val(newDistance);
        currentMeasure = newMeasure;

    });


});

function convert(from, to, dist) {

    var conv;
    switch (from + to) {
        
        // convert from meters
        case 'MeterKilometer':
            conv = dist * 0.001;
            break;
        case 'MeterMile':
            conv = dist * 0.00062137119223733;
            break;
        case 'MeterMeter':
            conv = dist * 1;
            break;


        // convert from miles
        case 'MileKilometer':
            conv = dist * 1.609344;
            break;
        case 'MileMile':
            conv = dist * 1;
            break;
        case 'MileMeter':
            conv = dist * 1609.344;
            break;

        // convert from kilometer
        case 'KilometerKilometer':
            conv = dist * 1;
            break;

        case 'KilometerMile':
            conv = dist * 0.62137119223733;
            break;
        case 'KilometerMeter':
            conv = dist * 1000;
            break;

    }
    //alert(conv);
    convr = Math.ceil(conv*1000)/1000;
    return convr;
}

Open in new window


HTML
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
<form>

    <div class="form-group">
      <label>Distance</label>
      <select id="distanceSelect" name="distanceSelect">
            <option value="">Custom</option>
            <option value="42195">Marathon</option>
            <option value="21097.5">Half-Marathon</option>
            <option value="5000">5K</option>
            <option value="10000">10K</option>
            <option value="25000">25K</option>
            <option value="30000">30K</option>
            <option value="50000">50K</option>
            <option value="80467.2">50M</option>
            <option value="100000">100K</option>
            <option value="160934">100M</option>
        </select>
      
      <input id="distance"  type="text" name="distance" > 
      <select id="distanceUnit">
	    <option value="Kilometer">Kilometer</option>
        <option value="Mile">Mile</option>
		<option value="Meter">Meter</option>
	  </select>
      
      
        
        
    </div>
</form>
</body>
</html>

Open in new window

LVL 55
Scott Fell, EE MVEDeveloper & EE ModeratorAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

RobOwner (Aidellio)Commented:
Floating point arithmetic is what JavaScript uses.  Considered accurate to 15 decimal places.  Your calculation goes past that.
0
RobOwner (Aidellio)Commented:
Do you need that level of accuracy?
0
RobOwner (Aidellio)Commented:
// change
convr = Math.ceil(conv*1000)/1000;
to
convr = conv.toFixed(2);
1

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

d-glitchCommented:
The first modern Olympic Marathon was 26 mi 385 yd.

I can convert this perfectly to 42,194.988 meters with my HP-15C.

Wikipedia rounds this up to 42,195  which is an error of 1.2 cm   or   0.28 parts per million.

I can convert 42,194.988 meters  perfectly to  42.194988 km by moving the decimal point.

If you get 42.197 this is more than odd, it is wrong.  

The magnitude of this error is remarkably   1.000E-06  or 0.00000100.

I think that this means that there is a real error (not a round off error) in the 6th digit of the hidden?? conversion factor.

1 inch = 0.0254 meters exactly.   It is possible to calculate the conversion factors for English and metric distances (or their reciprocals) perfectly with no round off error.
1
RobOwner (Aidellio)Commented:
It's a JavaScript issue: http://www.w3schools.com/js/js_numbers.asp

You were almost there with the *1000/1000. As you can see in the reference, the suggestion is to do the factor of ten multiplication at the time of initial calculation. I.e. At each conversion line
0
d-glitchCommented:
You can restrict yourself to integer arithmetic.  
This is a recommended approach for critical software from the days of microprocessors and assembly language.

Let your basic unit  ==>  1 micron  ==>  0.001 mm  ==>  0.000001 m

1 mm  =           1000 u
1 m   =      1,000,000 u
1 km  =  1,000,000,000 u

1 in  =        254,000 u
1 ft  =      3,048,000 u
1 mi  = 16,093,440,000 u

1 Marathon  =  421,949,880,000 u  <==  And this is still only 12 digits.

So you can take this about 1000x further, which would get you to the 
moon with 1 micron precision.

Open in new window

1
Scott Fell, EE MVEDeveloper & EE ModeratorAuthor Commented:
Thank you! Both are answers I was looking for.  I ended up with toFixed(3).  However, d-glitch's solution is brilliant.
0
Scott Fell, EE MVEDeveloper & EE ModeratorAuthor Commented:
I want to let you know if an update where I am using d-glitch's micron conversion and it works. However, the key is to not doing any rounding because that will of course mess things up especially going from miles to metric.  The work around would be to store and calculate on a hidden variable and display something rounded. I am sticking with keeping the raw value.  http://jsbin.com/codowocore/edit?html,js,output

$(function() {

    // select length of run
    var currentMeasure = $('select#distanceUnit option:selected').text(); // current distance unit (miles, meters)
    $('#distanceSelect').on('change', function() { // get the distance from drop down
        var distanceSelect = $('#distanceSelect').val();
        var convertTo = $('select#distanceUnit option:selected').text(); // convert from meters or what is currently selected to new measure
        if (distanceSelect !== '') {
            // convert distance to selected distance unit
            var c = convert('Meter', convertTo, distanceSelect);
            // place converted lenght in text box
            $('#distance').val(c);
        }

    });

    // recalculate the distance measure if change unit of measure
    $('#distanceUnit').on('change', function() {

        var currentDistance = $('#distance').val();
        var newMeasure = $(this).val();

        var newDistance = convert(currentMeasure, newMeasure, currentDistance);


        $('#distance').val(newDistance);
        currentMeasure = newMeasure;

    });


});

function convert(convertFrom, convertTo, dist) {
    //alert(convertTo+convertFrom);
    var conv;
    switch (convertFrom + convertTo) {



        // convert from meters
        case 'MeterKilometer':
            conv = dist * 1000000;
            conv = conv / 1000000000;

            break;
        case 'MeterMile':
            conv = dist * 1000000;
            conv = conv / 1609344000;

            break;
        case 'MeterMeter':
            conv = dist * 1;

            break;


            // convert from miles
        case 'MileKilometer':
            conv = dist * 1609344000;
            conv = conv / 1000000000;
            break;
        case 'MileMile':
            conv = dist * 1;
            break;
        case 'MileMeter':
            conv = dist * 1609344000;
            conv = conv / 1000000;
            break;

            // convert from kilometer
        case 'KilometerKilometer':
            conv = dist * 1;
            break;

        case 'KilometerMile':
            conv = dist * 1000000000;
            conv = conv / 1609344000;
            break;
        case 'KilometerMeter':
            conv = dist * 1000000000;
            conv = conv / 1000000;
            break;




    }

    return conv;

}

Open in new window

0
Scott Fell, EE MVEDeveloper & EE ModeratorAuthor Commented:
One other note, the conversion of microns and miles is off

1 mi  = 16,093,440,000 u is what is listed and
it should be
1 mi  = 1,609,344,000 u
1
d-glitchCommented:
>>   the conversion of microns and miles is off  [by a factor of 10]

Sorry about that.  Java may good for 15 digits, but my HP-15C is only good for 9, so I was trying to keep track of the decimal point in my head.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
JavaScript

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.