2

I want to convert an integer to the fractional part of a number using javascript.

For example:

  • 10030 -> 0.10030

  • 123 -> 0.123

I've come up with two ways of doing this:

var convertIntegerPartToFractionalPart1 = function(integerPart) {
    var fractionalPart = integerPart;

    while(fractionalPart > 1) {
        fractionalPart = fractionalPart / 10;
    }
    return fractionalPart;
};

var convertIntegerPartToFractionalPart2 = function(integerPart) {
    return parseFloat('.' + integerPart);
};

convertIntegerPartToFractionalPart1 does not produce 100% accurate results, for example 132232 is converted to 0.13223200000000002. However convertIntegerPartToFractionalPart1 is more than twice as fast as convertIntegerPartToFractionalPart2 under node.js on my MacBook Pro. (1000000 runs of convertIntegerPartToFractionalPart1 took 46ms, 1000000 runs of convertIntegerPartToFractionalPart2 took 96ms)

Is there a better way of doing this?

alexbirkett
  • 2,604
  • 2
  • 26
  • 30
  • 1
    The observation in method 1 would be clear upon reading [What Every Computer Scientist Should Know About Floating Point Arithmetic](http://www.cse.msu.edu/~cse320/Documents/FloatingPoint.pdf) – devnull May 24 '13 at 13:25
  • You could do something like: `factionalPart = integerPart / (10 ^ ceil(log10(integerPart)))` [note this is pseudocode since you'd have to do your own log10 function based upon natural log in javascrit and use `Math.` for lib calls]. I suspect in the end, this will not be as good as your option 1. So my vote would be option 1 if you care more about time, and option 2 if you care about the result being perfect. :) – lurker May 24 '13 at 13:32
  • @mbratch doing it that way helps for some larger integers, but there'll always be problems (as devnull points out) – Pointy May 24 '13 at 13:35
  • @Pointy, Yes I agree. I said in my comment it may not, in the end, be any better than option 1 (paraphrasing). – lurker May 24 '13 at 13:35
  • Your second method (if your original number is always an integer) would be most accurate (no floating point precision errors to deal with), however you'd need to test for decimal places in the parameter, that it's of type `Number` and that it isn't `Infinity` or `NaN`. – Qantas 94 Heavy May 24 '13 at 13:37
  • Maybe I'm doing it wrong, but I can't make @mbratch suggestion work `var convertIntegerPartToFractionalPartMbratch = function(integerPart) { return integerPart / (10 ^ Math.floor(1 + log10(integerPart))) }; var log10 = function(number) { return Math.log(number) / Math.log(10); };´ – alexbirkett May 24 '13 at 13:48
  • @alexbirkett check my answer; it's what he suggests basically. – Pointy May 24 '13 at 13:49
  • @alexbirkett ..i think my answer will satisfy you. Have a look. – Sudarshan Tanwar May 24 '13 at 14:23
  • check my jsfiddle demo link also. here is a working sample. – Sudarshan Tanwar May 24 '13 at 14:24

4 Answers4

2

Try this:

function cvt3(n) {
  return n / Math.pow(10, Math.ceil(Math.log(n)/Math.LN10));
}

It's still going to be possible that the result will not be exact, due to the nature of binary floating point (I think). But doing just one division might help. For smaller numbers your iteration might be just as good, and faster.

console.log( cvt3(132232) ); // 0.132232 

edit the version by Mr. Monosodium Glutamate is faster!

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • You should always be dividing by an integer, so I don't think that it would be a signficant issue. Usually, you only really see issues where floating point numbers are divided or multiplied numerous times, so (for the most part) this should not be an issue. – Qantas 94 Heavy May 24 '13 at 13:46
  • @Qantas94Heavy and yet the iterative divide-by-10 method introduces an artifact. – Pointy May 24 '13 at 13:48
  • @Qantas94Heavy ... but maybe that's because 10 is being divided into a non-integer. – Pointy May 24 '13 at 13:50
  • And it's done multiple times. After the first time, it's a floating point divide. So I think the pow10 method may be better in that regard. It eliminates the iterated variances. – lurker May 24 '13 at 13:51
  • ... and I forget the fundamental part of how numbers are represented in JavaScript. Indeed this is the case over large numbers of divisions - once again I'd prove to be wrong. `Math.log(10)/Math.log(2); // 3.3219280948873626` – Qantas 94 Heavy May 24 '13 at 13:53
  • It is a marginally faster, a million runs of cvt3(132232) take 41ms. – alexbirkett May 24 '13 at 13:59
2

I first didn't want to answer, as Pointys solution seems far more elegant.

But after doing a Jsperf it turned out the Math solution was about 70% slower for me on chrome.

function cnvrt3 (n) {
  return n / Math.pow(10,(""+n).length)
}
cnvrt3(132232)//0.132232 

So heres the same using casting to determine the power of ten

Note due to the floating point precision 0.132232 is not really 0.132232. Though most likely the value you are looking for

Community
  • 1
  • 1
Moritz Roessler
  • 8,542
  • 26
  • 51
0

You won't maintain numbers with trailing zeroes, as in your example:

10030 ->0.10030

but you can prepend a dot in front of a string:

'.'+String(10030)-> '.10030'
kennebec
  • 102,654
  • 32
  • 106
  • 127
0

Here is best approach to so this :

Demo Here

    function ab() {
        var a = 566123;

        var len = a.toString().length;
        var decimalPoints = 1;

        for (var i = 0; i < len; i++) {
            decimalPoints = decimalPoints * 10;
        }

        var number = parseInt(a) / decimalPoints;
        alert(number);
    }
Sudarshan Tanwar
  • 3,537
  • 3
  • 24
  • 39