JavaScript Number Formatting

JavaScript (as you programmers will attest) is a REAL pain, especially when it comes to formatting numbers for output. Currency can be done easily enough (forcing trailing zeroes, forcing decimals, etc).
However, really huge (or really small numbers) are difficult to format because JavaScript doesn’t show scientific notation between approximately E+20 and E-20 and you are left with difficult to read output such as
2377654326543.7652853 (NO commas of course) OR
.00000000000000000139735

I have found a way to format the numbers:
http://www.chimie.fundp.ac.be/javas/js_format.html
However, this ends up making the numbers appear the way a calculator shows them: .657E+25.
Is there any way to make the output in traditional scientific notation 6.57 E+24 ?
Thank you.

The easiest way would be to write your own formatting function. I was bored, so I whipped this up, sadly, my knowledge of E notation is lacking, let me know if it needs corrections:


function fFormatToE( inNumber )
{
	var $sTempN;

	$n = inNumber;

	// work with absolute value
	var $nAbsolute = Math.abs( $n );

	// convert to string
	var $sN = $nAbsolute.toString();

	// get postion of decimal point
	$nDecimal = $sN.indexOf( "." );

	// ------------------------------------------
	// reformat raw number to X.XXXXXXXXXX format
	// ------------------------------------------
	$sTempN = $sN;

	// handle leading 0s
	if( $nDecimal == 0 )
	{
		while( $sTempN.substring( 0, 1 ) == '0' )
		{
			$nZeroOffset++;
			$sTempN = $sTempN.substring( 1, $sTempN.length );
		}
	}
	else if( $nDecimal == -1 )
	{
		$nDecimal = $sN.length;
	}

	$sRawNumber = $sTempN.substring( 0,1 ) + '.' + $sTempN.substring( 1, $nDecimal ) + $sTempN.substring( $nDecimal + 1, $sTempN.length );

	// ===========================================================================
	// Number is 0
	// ===========================================================================
	if( $nAbsolute == 0 )
	{
		$output = '0.0 E+0';
	}

	// ===========================================================================
	// Numbers greater than 1
	// ===========================================================================
	else if ($nAbsolute >= 1)
	{
		// ----------------------------
		// determine order of magnitude
		// ----------------------------
		$nOrder = $nDecimal - 1;
		$sOrder = ( $nOrder < 10 ) ? ( '0' + $nOrder ) : $nOrder;

		$sENumber = $sRawNumber + ' E+' + $sOrder;
	}

	// ===========================================================================
	//	Numbers less than 1
	// ===========================================================================
	else if ($nAbsolute < 1.0)
	{
		// ----------------------------
		// determine order of magnitude
		// ----------------------------

		$nOrder = $nZeroOffset + 1;
		$sOrder = ( $nOrder < 10 ) ? ( '0' + $nOrder ) : $nOrder;

		$sENumber = $sRawNumber + ' E-' + $sOrder;
	}
	// ===========================================================================
	//	Positive Numbers
	// ===========================================================================
	if( $n > 0 )
	{
		$output = '+' + $sENumber;
	}

	// ===========================================================================
	//	Negative Numbers
	// ===========================================================================
	else if( $n < 0 )
	{
		$output = '-' + $sENumber;
	}

	// ===========================================================================
	// Number is 0 (just to catch it again)
	// ===========================================================================
	else
	{
		$output = '0.0 E+0';
	}

	return $output;
}

Seemed to work fine in my quick test. Be advised that if alpha characters are included, it will return a result of 0.0 E+0.

Doh, found a bug when testing your two example numbers, here’s the updated function:


function fFormatToE( inNumber )
{
	var $sTempN;
	var $sRawNumber;
	var $nZeroOffset = 0;

	$n = inNumber;

	// work with absolute value
	var $nAbsolute = Math.abs( $n );

	//check to see if it was automatically converted by absolute
	if( $nAbsolute.toString().indexOf( "e" ) )
	{
		return $nAbsolute;
	}

	// convert to string
	var $sN = $nAbsolute.toString();

	// get postion of decimal point
	$nDecimal = $sN.indexOf( "." );

	// ------------------------------------------
	// reformat raw number to X.XXXXXXXXXX format
	// ------------------------------------------
	$sTempN = $sN;

	// handle leading 0s
	if( ($nDecimal == 1) && ($nAbsolute < 1) )
	{
		while( $sTempN.substring( 1, 2 ) == '0' )
		{
			$nZeroOffset++;
			$sTempN = $sTempN.substring( 1, $sTempN.length );
		}
	}
	else if( $nDecimal == -1 )
	{
		$nDecimal = $sN.length;
	}

	if( $nAbsolute < 1 )
	{
		$sRawNumber = $sTempN.substring( 2,3 ) + '.' + $sTempN.substring( 3, $sTempN.length );
	}
	else
	{
		$sRawNumber = $sTempN.substring( 0,1 ) + '.' + $sTempN.substring( 1, $nDecimal ) + $sTempN.substring( $nDecimal + 1, $sTempN.length );
	}

	// ===========================================================================
	// Number is 0
	// ===========================================================================
	if( $nAbsolute == 0 )
	{
		$output = '0.0 e+0';
	}

	// ===========================================================================
	// Numbers greater than 1
	// ===========================================================================
	else if ($nAbsolute >= 1)
	{
		// ----------------------------
		// determine order of magnitude
		// ----------------------------
		$nOrder = $nDecimal - 1;
		$sOrder = ( $nOrder < 10 ) ? ( '0' + $nOrder ) : $nOrder;

		$sENumber = $sRawNumber + ' e+' + $sOrder;
	}

	// ===========================================================================
	//	Numbers less than 1
	// ===========================================================================
	else if ($nAbsolute < 1.0)
	{
		// ----------------------------
		// determine order of magnitude
		// ----------------------------

		$nOrder = $nZeroOffset + 1;
		$sOrder = ( $nOrder < 10 ) ? ( '0' + $nOrder ) : $nOrder;

		$sENumber = $sRawNumber + ' e-' + $sOrder;
	}
	// ===========================================================================
	//	Positive Numbers
	// ===========================================================================
	if( $n > 0 )
	{
		$output = '+' + $sENumber;
	}

	// ===========================================================================
	//	Negative Numbers
	// ===========================================================================
	else if( $n < 0 )
	{
		$output = '-' + $sENumber;
	}

	// ===========================================================================
	// Number is 0 (just to catch it again)
	// ===========================================================================
	else
	{
		$output = '0.0 e+0';
	}

	return $output;
}

Also, the function will return NaN (not a number) if an alpha character is entered, OR, if you enter a number that has an E in it, it will return infinity.

DOH, forgot one last error check.

change


	if( $nAbsolute.toString().indexOf( "e" ) )


to


	if( $nAbsolute.toString().indexOf( "e" ) > 0 )

ugh, one more. I should really bug test more before posting…

Change line 32


		while( $sTempN.substring( 1, 2 ) == '0' )

To


		while( $sTempN.substring( 2, 3 ) == '0' )

As Regis Philbin would say “Is that your final answer?”
Seriously wet marble, thanks for the quick reply and sorry for taking so long to respond to your answer. I haven’t tested it out yet. If it turns out to be precisely what I wanted, could I use it on my website www.1728.com ? OR perhaps I could make substantial changes to it to make it “mine”? If anything, I will probably use the rounding routine from now on. I really don’t feel like going back and changing a couple of dozen calculators.
Thanks again.

Feel free to use it as you see fit. = )

Thanks wet marble.
Occassionally I have written some things for people that have requested it through E-Mail. (For example - someone wanted to know how to fomat currency in an order form they were designing.)

Anyway I just thought I’d ask you to see if it was okay.
Thanks again.

wet marble
I tested your rounding routine and it works very well except when the numbers get automatically formatted by JavaScript, the rounding routine does nothing.
So, I changed some lines and added a switch (sw) to detect numbers outside of the rounding routine. Admittedly, I took the easy way out by just having the number appear in the output box with no testing or formatting.
Well, what do you think? I’m also thinking of having an option for a user to choose how many significant decimal places they want.

Anyway, your routine does work.

<HTML>
<TITLE>JavaScript Formatting</TITLE>
<HEAD>
<script>
var sw=0;
var $n=0;
var ct=0;
</script>
<script>
function fFormatToE()
{
sw=1;
var inNumber;
var $sTempN;
var $sRawNumber;
var $nZeroOffset = 0;
<!–$n = inNumber;–>
$n=eval(document.boxes.numin.value);
if ($n>1e-06 && $n<1e21){sw=0};
if (sw==1){$output=" " + $n};
if (sw==0){
// work with absolute value
var $nAbsolute = Math.abs( $n );

//check to see if it was automatically converted by absolute
if( $nAbsolute.toString().indexOf( "e" ) &gt; 0 )	    
{
    return $nAbsolute;
}

// convert to string
var $sN = $nAbsolute.toString();

// get postion of decimal point
$nDecimal = $sN.indexOf( "." );

// ------------------------------------------
// reformat raw number to X.XXXXXXXXXX format
// ------------------------------------------
$sTempN = $sN;

// handle leading 0s
if( ($nDecimal == 1) && ($nAbsolute &lt; 1) )
{
    while( $sTempN.substring( 2, 3 ) == '0' )
    {
        $nZeroOffset++;
        $sTempN = $sTempN.substring( 1, $sTempN.length );
    }
}
else if( $nDecimal == -1 )
{
    $nDecimal = $sN.length;
}

if( $nAbsolute &lt; 1 )
{
    $sRawNumber = $sTempN.substring( 2,3 ) + '.' + $sTempN.substring( 3, $sTempN.length );
}
else
{
    $sRawNumber = $sTempN.substring( 0,1 ) + '.' + $sTempN.substring( 1, $nDecimal ) + $sTempN.substring( $nDecimal + 1, $sTempN.length );
}

 // Number is 0
//====================

if( $nAbsolute == 0 )
{
    $output = '0.0 e+0';
}

// Numbers greater than 1
// =================    

else if ($nAbsolute &gt;= 1)
{
    // ----------------------------
    // determine order of magnitude
    // ----------------------------
    $nOrder = $nDecimal - 1;
    $sOrder = ( $nOrder &lt; 10 ) ? ( '0' + $nOrder ) : $nOrder;

    $sENumber = $sRawNumber + ' e+' + $sOrder;
}

//==========================
//    Numbers less than 1
//==========================    

else if ($nAbsolute &lt; 1.0)
{
    // ----------------------------
    // determine order of magnitude
    // ----------------------------

    $nOrder = $nZeroOffset + 1;
    $sOrder = ( $nOrder &lt; 10 ) ? ( '0' + $nOrder ) : $nOrder;

    $sENumber = $sRawNumber + ' e-' + $sOrder;
}
//    Positive Numbers
//=======================    

if( $n &gt; 0 )
{
    $output = '+' + $sENumber;
}

//    Negative Numbers
//==========================    

else if( $n &lt; 0 )
{
    $output = '-' + $sENumber;
}

// Number is 0 (just to catch it again)
//=================

else
{
    $output = '0.0 e+0';
}

}
document.boxes.numout.value=$output;

}
</script>

</HEAD>
<!-- B O D Y ***********************************–>
<BODY BGCOLOR="#FFFFFF">
<font color="#0000FF">
JavaScript Formatting Routine
<FORM NAME=“boxes”>
<!-- THIS IS THE INPUT BOX -->
INPUT NUMBER=<INPUT TYPE=“number” NAME=“numin” SIZE=60>
<p>
<CENTER>
<INPUT TYPE=“button” VALUE=“CALCULATE” OnClick=“fFormatToE()”>
</CENTER>
<p>
<!-- THIS IS THE OUTPUT BOX -->
OUTPUT NUMBER=<INPUT TYPE=“number” NAME=“numout” SIZE=60>
<p>
</FORM>
</BODY>
</HTML>

Great green gravy, that’s a lot of code. You realize that JavaScript 1.5 has a toExponential method with the Number object, right? Even if you’re worried about this function not being there, I would suggest at least putting this line at the beginning of the function:

if (inNumber.toExponential) return inNumber.toExponential(2)

I shouldn’t have said that. I realize now that I have a more compact coding style, so it just looked like a lot of code to me. But I did write a function with a somewhat different approach - it works on the numerical value rather than the string. I think the outputs are all the same. Which way you do it I guess depends on your project. Here’s the code, anyway, even though I think you’ve already gotten a good solution.

function MakeExponential(inNumber, digits) {
  if (inNumber.toExponential) return inNumber.toExponential(digits)
  if (inNumber == 0) return "0.0e+0"
  if (inNumber < 0) return "-" + MakeExponential(-inNumber, digits)
  Characteristic = Math.floor(Math.log(inNumber) * Math.LOG10E)
  Mantissa = inNumber * Math.pow(10, -Characteristic)
  return Mantissa.toString().substr(0, digits+2) +
    (Characteristic < 0 ? "e" : "e+") + Characteristic;
}

(BTW, I do know that what I called the mantissa is actually the antilog of the mantissa. Variable names can only be so descriptive. ;))

Achernar
Perhaps I did not make it clear but wet marble wrote 99% of that rounding routine. I just added some lines to handle numbers when they go into exponential notation and I added the HTML just to make it run, so to speak.

So, when you said “I think you’ve already gotten a good solution” - the praise goes to wet marble.

And thanks Achernar for your solution. (Haven’t tried it out yet.)

Achernar
JavaScript now has a number formatting routine? :smack:
So, does this negate what the 3 of us have been attempting?
So, all that code can be reduced to somethng as simple as these 3 lines ?

<HTML>
<TITLE>JavaScript Formatting</TITLE>
<HEAD>
<script>
var num=0;
</script>

<script>
function FormatExp()
{
<!-- THESE 3 LINES–>
num=eval(document.boxes.numin.value);
num=num.toExponential(4) ;
document.boxes.numout.value=" "+num;
<!-- END OF THESE 3 LINES -->
}
</script>

</HEAD>

<BODY BGCOLOR="#FFFFFF">
<font color="#0000FF">
JavaScript Formatting Routine
<FORM NAME=“boxes”>
<!-- THIS IS THE INPUT BOX -->
INPUT NUMBER=<INPUT TYPE=“number” NAME=“numin” SIZE=60>
<p>
<CENTER>
<INPUT TYPE=“button” VALUE=“CALCULATE” OnClick=“FormatExp()”>
</CENTER>
<p>
<!-- THIS IS THE OUTPUT BOX -->
OUTPUT NUMBER=<INPUT TYPE=“number” NAME=“numout” SIZE=60>
<p>
</FORM>
</BODY>
</HTML>

:smack:

So, JavaScript finallyhas a number formatting routine?
Well, to express this in technical terms:
** It’s about %%^&*&**&&##%&&&%%##@#@ time !!!

I guess I should go to more “up-to-date” JavaScript websites. Any suggestions?

DevEdge is what I use. Here’s their listing for the toExponential method.

Thanks Achernar
So, unless somebody is using an OLD browser, that formatting method (toExponential) should display correctly ?
Anyway, it displays just fine on Internet Explorer on my machine and IE is used by about 80% of the Internet surfing public.

holy crap, they added a number format function? that’s not fair.

pouts

oh well. it was a fun exercise anyway. As you can probably tell, I pretty much stopped developing javascript back at version 1.2.

wet marble
Yeah, I keep relying on the text I bought about 5 years ago.
Sheesh, I had noticed some sites that were asking people to choose significant figures and I thought they were just using the “Brute force method” (aka ‘write your own formatting’).

I should keep more aware of changes in technology. Maybe someday we’ll put a man on the Moon.

Achernar and wet marble
Please take a look at the “new and improved” Ultra Converter.
www.1728.com/convert.htm

I don’t mean to turn this into “The Thread That Wouldn’t Die”, but here is another discovery. The JavaScript exponential formatting does NOT work with an Opera browser. So, I added an option to eliminate ALL formatting for those uncooperative browsers.

Is it possible that the Internet could become even less standardized than it already is?
To view this posting properly, you must be using Internet Explorer 6, Real Player 7, Shockwave 8, Red Sox 9 and Yankees 10. Film at 11.

Well, both the function wet marble wrote and the one I wrote work in Opera, it seems. So you may not have to abandon such formatting altogether.