Related
I have this line of code which rounds my numbers to two decimal places. But I get numbers like this: 10.8, 2.4, etc. These are not my idea of two decimal places so how I can improve the following?
Math.round(price*Math.pow(10,2))/Math.pow(10,2);
I want numbers like 10.80, 2.40, etc. Use of jQuery is fine with me.
To format a number using fixed-point notation, you can simply use the toFixed method:
(10.8).toFixed(2); // "10.80"
var num = 2.4;
alert(num.toFixed(2)); // "2.40"
Note that toFixed() returns a string.
IMPORTANT: Note that toFixed does not round 90% of the time, it will return the rounded value, but for many cases, it doesn't work.
For instance:
2.005.toFixed(2) === "2.00"
UPDATE:
Nowadays, you can use the Intl.NumberFormat constructor. It's part of the ECMAScript Internationalization API Specification (ECMA402). It has pretty good browser support, including even IE11, and it is fully supported in Node.js.
const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
console.log(formatter.format(2.005)); // "2.01"
console.log(formatter.format(1.345)); // "1.35"
You can alternatively use the toLocaleString method, which internally will use the Intl API:
const format = (num, decimals) => num.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
console.log(format(2.005)); // "2.01"
console.log(format(1.345)); // "1.35"
This API also provides you a wide variety of options to format, like thousand separators, currency symbols, etc.
This is an old topic but still top-ranked Google results and the solutions offered share the same floating point decimals issue. Here is the (very generic) function I use, thanks to MDN:
function round(value, exp) {
if (typeof exp === 'undefined' || +exp === 0)
return Math.round(value);
value = +value;
exp = +exp;
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
return NaN;
// Shift
value = value.toString().split('e');
value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
// Shift back
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}
As we can see, we don't get these issues:
round(1.275, 2); // Returns 1.28
round(1.27499, 2); // Returns 1.27
This genericity also provides some cool stuff:
round(1234.5678, -2); // Returns 1200
round(1.2345678e+2, 2); // Returns 123.46
round("123.45"); // Returns 123
Now, to answer the OP's question, one has to type:
round(10.8034, 2).toFixed(2); // Returns "10.80"
round(10.8, 2).toFixed(2); // Returns "10.80"
Or, for a more concise, less generic function:
function round2Fixed(value) {
value = +value;
if (isNaN(value))
return NaN;
// Shift
value = value.toString().split('e');
value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + 2) : 2)));
// Shift back
value = value.toString().split('e');
return (+(value[0] + 'e' + (value[1] ? (+value[1] - 2) : -2))).toFixed(2);
}
You can call it with:
round2Fixed(10.8034); // Returns "10.80"
round2Fixed(10.8); // Returns "10.80"
Various examples and tests (thanks to #t-j-crowder!):
function round(value, exp) {
if (typeof exp === 'undefined' || +exp === 0)
return Math.round(value);
value = +value;
exp = +exp;
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
return NaN;
// Shift
value = value.toString().split('e');
value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
// Shift back
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}
function naive(value, exp) {
if (!exp) {
return Math.round(value);
}
var pow = Math.pow(10, exp);
return Math.round(value * pow) / pow;
}
function test(val, places) {
subtest(val, places);
val = typeof val === "string" ? "-" + val : -val;
subtest(val, places);
}
function subtest(val, places) {
var placesOrZero = places || 0;
var naiveResult = naive(val, places);
var roundResult = round(val, places);
if (placesOrZero >= 0) {
naiveResult = naiveResult.toFixed(placesOrZero);
roundResult = roundResult.toFixed(placesOrZero);
} else {
naiveResult = naiveResult.toString();
roundResult = roundResult.toString();
}
$("<tr>")
.append($("<td>").text(JSON.stringify(val)))
.append($("<td>").text(placesOrZero))
.append($("<td>").text(naiveResult))
.append($("<td>").text(roundResult))
.appendTo("#results");
}
test(0.565, 2);
test(0.575, 2);
test(0.585, 2);
test(1.275, 2);
test(1.27499, 2);
test(1234.5678, -2);
test(1.2345678e+2, 2);
test("123.45");
test(10.8034, 2);
test(10.8, 2);
test(1.005, 2);
test(1.0005, 2);
table {
border-collapse: collapse;
}
table, td, th {
border: 1px solid #ddd;
}
td, th {
padding: 4px;
}
th {
font-weight: normal;
font-family: sans-serif;
}
td {
font-family: monospace;
}
<table>
<thead>
<tr>
<th>Input</th>
<th>Places</th>
<th>Naive</th>
<th>Thorough</th>
</tr>
</thead>
<tbody id="results">
</tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I usually add this to my personal library, and after some suggestions and using the #TIMINeutron solution too, and making it adaptable for decimal length then, this one fits best:
function precise_round(num, decimals) {
var t = Math.pow(10, decimals);
return (Math.round((num * t) + (decimals>0?1:0)*(Math.sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals);
}
will work for the exceptions reported.
FAST AND EASY
parseFloat(number.toFixed(2))
Example
let number = 2.55435930
let roundedString = number.toFixed(2) // "2.55"
let twoDecimalsNumber = parseFloat(roundedString) // 2.55
let directly = parseFloat(number.toFixed(2)) // 2.55
One way to be 100% sure that you get a number with 2 decimals:
(Math.round(num*100)/100).toFixed(2)
If this causes rounding errors, you can use the following as James has explained in his comment:
(Math.round((num * 1000)/10)/100).toFixed(2)
I don't know why can't I add a comment to a previous answer (maybe I'm hopelessly blind, I don't know), but I came up with a solution using #Miguel's answer:
function precise_round(num,decimals) {
return Math.round(num*Math.pow(10, decimals)) / Math.pow(10, decimals);
}
And its two comments (from #bighostkim and #Imre):
Problem with precise_round(1.275,2) not returning 1.28
Problem with precise_round(6,2) not returning 6.00 (as he wanted).
My final solution is as follows:
function precise_round(num,decimals) {
var sign = num >= 0 ? 1 : -1;
return (Math.round((num*Math.pow(10,decimals)) + (sign*0.001)) / Math.pow(10,decimals)).toFixed(decimals);
}
As you can see I had to add a little bit of "correction" (it's not what it is, but since Math.round is lossy - you can check it on jsfiddle.net - this is the only way I knew how to "fix" it). It adds 0.001 to the already padded number, so it is adding a 1 three 0s to the right of the decimal value. So it should be safe to use.
After that I added .toFixed(decimal) to always output the number in the correct format (with the right amount of decimals).
So that's pretty much it. Use it well ;)
EDIT: added functionality to the "correction" of negative numbers.
toFixed(n) provides n length after the decimal point; toPrecision(x)
provides x total length.
Use this method below
// Example: toPrecision(4) when the number has 7 digits (3 before, 4 after)
// It will round to the tenths place
num = 500.2349;
result = num.toPrecision(4); // result will equal 500.2
AND if you want the number to be fixed use
result = num.toFixed(2);
I didn't find an accurate solution for this problem, so I created my own:
function inprecise_round(value, decPlaces) {
return Math.round(value*Math.pow(10,decPlaces))/Math.pow(10,decPlaces);
}
function precise_round(value, decPlaces){
var val = value * Math.pow(10, decPlaces);
var fraction = (Math.round((val-parseInt(val))*10)/10);
//this line is for consistency with .NET Decimal.Round behavior
// -342.055 => -342.06
if(fraction == -0.5) fraction = -0.6;
val = Math.round(parseInt(val) + fraction) / Math.pow(10, decPlaces);
return val;
}
Examples:
function inprecise_round(value, decPlaces) {
return Math.round(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
function precise_round(value, decPlaces) {
var val = value * Math.pow(10, decPlaces);
var fraction = (Math.round((val - parseInt(val)) * 10) / 10);
//this line is for consistency with .NET Decimal.Round behavior
// -342.055 => -342.06
if (fraction == -0.5) fraction = -0.6;
val = Math.round(parseInt(val) + fraction) / Math.pow(10, decPlaces);
return val;
}
// This may produce different results depending on the browser environment
console.log("342.055.toFixed(2) :", 342.055.toFixed(2)); // 342.06 on Chrome & IE10
console.log("inprecise_round(342.055, 2):", inprecise_round(342.055, 2)); // 342.05
console.log("precise_round(342.055, 2) :", precise_round(342.055, 2)); // 342.06
console.log("precise_round(-342.055, 2) :", precise_round(-342.055, 2)); // -342.06
console.log("inprecise_round(0.565, 2) :", inprecise_round(0.565, 2)); // 0.56
console.log("precise_round(0.565, 2) :", precise_round(0.565, 2)); // 0.57
Here's a simple one
function roundFloat(num,dec){
var d = 1;
for (var i=0; i<dec; i++){
d += "0";
}
return Math.round(num * d) / d;
}
Use like alert(roundFloat(1.79209243929,4));
Jsfiddle
Round down
function round_down(value, decPlaces) {
return Math.floor(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
Round up
function round_up(value, decPlaces) {
return Math.ceil(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
Round nearest
function round_nearest(value, decPlaces) {
return Math.round(value * Math.pow(10, decPlaces)) / Math.pow(10, decPlaces);
}
Merged https://stackoverflow.com/a/7641824/1889449 and
https://www.kirupa.com/html5/rounding_numbers_in_javascript.htm Thanks
them.
Building on top of Christian C. Salvadó's answer, doing the following will output a Number type, and also seems to be dealing with rounding well:
const roundNumberToTwoDecimalPlaces = (num) => Number(new Intl.NumberFormat('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(num));
roundNumberToTwoDecimalPlaces(1.344); // => 1.34
roundNumberToTwoDecimalPlaces(1.345); // => 1.35
The difference between the above and what has already been mentioned is that you don't need the .format() chaining when you're using it[, and that it outputs a Number type].
#heridev and I created a small function in jQuery.
You can try next:
HTML
<input type="text" name="one" class="two-digits"><br>
<input type="text" name="two" class="two-digits">
jQuery
// apply the two-digits behaviour to elements with 'two-digits' as their class
$( function() {
$('.two-digits').keyup(function(){
if($(this).val().indexOf('.')!=-1){
if($(this).val().split(".")[1].length > 2){
if( isNaN( parseFloat( this.value ) ) ) return;
this.value = parseFloat(this.value).toFixed(2);
}
}
return this; //for chaining
});
});
DEMO ONLINE:
http://jsfiddle.net/c4Wqn/
The trouble with floating point values is that they are trying to represent an infinite amount of (continuous) values with a fixed amount of bits. So naturally, there must be some loss in play, and you're going to be bitten with some values.
When a computer stores 1.275 as a floating point value, it won't actually remember whether it was 1.275 or 1.27499999999999993, or even 1.27500000000000002. These values should give different results after rounding to two decimals, but they won't, since for computer they look exactly the same after storing as floating point values, and there's no way to restore the lost data. Any further calculations will only accumulate such imprecision.
So, if precision matters, you have to avoid floating point values from the start. The simplest options are to
use a devoted library
use strings for storing and passing around the values (accompanied by string operations)
use integers (e.g. you could be passing around the amount of hundredths of your actual value, e.g. amount in cents instead of amount in dollars)
For example, when using integers to store the number of hundredths, the function for finding the actual value is quite simple:
function descale(num, decimals) {
var hasMinus = num < 0;
var numString = Math.abs(num).toString();
var precedingZeroes = '';
for (var i = numString.length; i <= decimals; i++) {
precedingZeroes += '0';
}
numString = precedingZeroes + numString;
return (hasMinus ? '-' : '')
+ numString.substr(0, numString.length-decimals)
+ '.'
+ numString.substr(numString.length-decimals);
}
alert(descale(127, 2));
With strings, you'll need rounding, but it's still manageable:
function precise_round(num, decimals) {
var parts = num.split('.');
var hasMinus = parts.length > 0 && parts[0].length > 0 && parts[0].charAt(0) == '-';
var integralPart = parts.length == 0 ? '0' : (hasMinus ? parts[0].substr(1) : parts[0]);
var decimalPart = parts.length > 1 ? parts[1] : '';
if (decimalPart.length > decimals) {
var roundOffNumber = decimalPart.charAt(decimals);
decimalPart = decimalPart.substr(0, decimals);
if ('56789'.indexOf(roundOffNumber) > -1) {
var numbers = integralPart + decimalPart;
var i = numbers.length;
var trailingZeroes = '';
var justOneAndTrailingZeroes = true;
do {
i--;
var roundedNumber = '1234567890'.charAt(parseInt(numbers.charAt(i)));
if (roundedNumber === '0') {
trailingZeroes += '0';
} else {
numbers = numbers.substr(0, i) + roundedNumber + trailingZeroes;
justOneAndTrailingZeroes = false;
break;
}
} while (i > 0);
if (justOneAndTrailingZeroes) {
numbers = '1' + trailingZeroes;
}
integralPart = numbers.substr(0, numbers.length - decimals);
decimalPart = numbers.substr(numbers.length - decimals);
}
} else {
for (var i = decimalPart.length; i < decimals; i++) {
decimalPart += '0';
}
}
return (hasMinus ? '-' : '') + integralPart + (decimals > 0 ? '.' + decimalPart : '');
}
alert(precise_round('1.275', 2));
alert(precise_round('1.27499999999999993', 2));
Note that this function rounds to nearest, ties away from zero, while IEEE 754 recommends rounding to nearest, ties to even as the default behavior for floating point operations. Such modifications are left as an exercise for the reader :)
Round your decimal value, then use toFixed(x) for your expected digit(s).
function parseDecimalRoundAndFixed(num,dec){
var d = Math.pow(10,dec);
return (Math.round(num * d) / d).toFixed(dec);
}
Call
parseDecimalRoundAndFixed(10.800243929,4) => 10.80
parseDecimalRoundAndFixed(10.807243929,2) => 10.81
Number(Math.round(1.005+'e2')+'e-2'); // 1.01
This worked for me: Rounding Decimals in JavaScript
With these examples you will still get an error when trying to round the number 1.005 the solution is to either use a library like Math.js or this function:
function round(value: number, decimals: number) {
return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
}
Here is my 1-line solution: Number((yourNumericValueHere).toFixed(2));
Here's what happens:
1) First, you apply .toFixed(2) onto the number that you want to round off the decimal places of. Note that this will convert the value to a string from number. So if you are using Typescript, it will throw an error like this:
"Type 'string' is not assignable to type 'number'"
2) To get back the numeric value or to convert the string to numeric value, simply apply the Number() function on that so-called 'string' value.
For clarification, look at the example below:
EXAMPLE:
I have an amount that has upto 5 digits in the decimal places and I would like to shorten it to upto 2 decimal places. I do it like so:
var price = 0.26453;
var priceRounded = Number((price).toFixed(2));
console.log('Original Price: ' + price);
console.log('Price Rounded: ' + priceRounded);
In general, decimal rounding is done by scaling: round(num * p) / p
Naive implementation
Using the following function with halfway numbers, you will get either the upper rounded value as expected, or the lower rounded value sometimes depending on the input.
This inconsistency in rounding may introduce hard to detect bugs in the client code.
function naiveRound(num, decimalPlaces) {
var p = Math.pow(10, decimalPlaces);
return Math.round(num * p) / p;
}
console.log( naiveRound(1.245, 2) ); // 1.25 correct (rounded as expected)
console.log( naiveRound(1.255, 2) ); // 1.25 incorrect (should be 1.26)
Better implementations
By converting the number to a string in the exponential notation, positive numbers are rounded as expected.
But, be aware that negative numbers round differently than positive numbers.
In fact, it performs what is basically equivalent to "round half up" as the rule, you will see that round(-1.005, 2) evaluates to -1 even though round(1.005, 2) evaluates to 1.01. The lodash _.round method uses this technique.
/**
* Round half up ('round half towards positive infinity')
* Uses exponential notation to avoid floating-point issues.
* Negative numbers round differently than positive numbers.
*/
function round(num, decimalPlaces) {
num = Math.round(num + "e" + decimalPlaces);
return Number(num + "e" + -decimalPlaces);
}
// test rounding of half
console.log( round(0.5, 0) ); // 1
console.log( round(-0.5, 0) ); // 0
// testing edge cases
console.log( round(1.005, 2) ); // 1.01
console.log( round(2.175, 2) ); // 2.18
console.log( round(5.015, 2) ); // 5.02
console.log( round(-1.005, 2) ); // -1
console.log( round(-2.175, 2) ); // -2.17
console.log( round(-5.015, 2) ); // -5.01
If you want the usual behavior when rounding negative numbers, you would need to convert negative numbers to positive before calling Math.round(), and then convert them back to negative numbers before returning.
// Round half away from zero
function round(num, decimalPlaces) {
num = Math.round(Math.abs(num) + "e" + decimalPlaces) * Math.sign(num);
return Number(num + "e" + -decimalPlaces);
}
There is a different purely mathematical technique to perform round-to-nearest (using "round half away from zero"), in which epsilon correction is applied before calling the rounding function.
Simply, we add the smallest possible float value (= 1.0 ulp; unit in the last place) to the number before rounding. This moves to the next representable value after the number, away from zero.
/**
* Round half away from zero ('commercial' rounding)
* Uses correction to offset floating-point inaccuracies.
* Works symmetrically for positive and negative numbers.
*/
function round(num, decimalPlaces) {
var p = Math.pow(10, decimalPlaces);
var e = Number.EPSILON * num * p;
return Math.round((num * p) + e) / p;
}
// test rounding of half
console.log( round(0.5, 0) ); // 1
console.log( round(-0.5, 0) ); // -1
// testing edge cases
console.log( round(1.005, 2) ); // 1.01
console.log( round(2.175, 2) ); // 2.18
console.log( round(5.015, 2) ); // 5.02
console.log( round(-1.005, 2) ); // -1.01
console.log( round(-2.175, 2) ); // -2.18
console.log( round(-5.015, 2) ); // -5.02
This is needed to offset the implicit round-off error that may occur during encoding of decimal numbers, particularly those having "5" in the last decimal position, like 1.005, 2.675 and 16.235. Actually, 1.005 in decimal system is encoded to 1.0049999999999999 in 64-bit binary float; while, 1234567.005 in decimal system is encoded to 1234567.0049999998882413 in 64-bit binary float.
It is worth noting that the maximum binary round-off error is dependent upon (1) the magnitude of the number and (2) the relative machine epsilon (2^-52).
Put the following in some global scope:
Number.prototype.getDecimals = function ( decDigCount ) {
return this.toFixed(decDigCount);
}
and then try:
var a = 56.23232323;
a.getDecimals(2); // will return 56.23
Update
Note that toFixed() can only work for the number of decimals between 0-20 i.e. a.getDecimals(25) may generate a javascript error, so to accomodate that you may add some additional check i.e.
Number.prototype.getDecimals = function ( decDigCount ) {
return ( decDigCount > 20 ) ? this : this.toFixed(decDigCount);
}
Number(((Math.random() * 100) + 1).toFixed(2))
this will return a random number from 1 to 100 rounded to 2 decimal places.
Using this response by reference: https://stackoverflow.com/a/21029698/454827
I build a function to get dynamic numbers of decimals:
function toDec(num, dec)
{
if(typeof dec=='undefined' || dec<0)
dec = 2;
var tmp = dec + 1;
for(var i=1; i<=tmp; i++)
num = num * 10;
num = num / 10;
num = Math.round(num);
for(var i=1; i<=dec; i++)
num = num / 10;
num = num.toFixed(dec);
return num;
}
here working example: https://jsfiddle.net/wpxLduLc/
parse = function (data) {
data = Math.round(data*Math.pow(10,2))/Math.pow(10,2);
if (data != null) {
var lastone = data.toString().split('').pop();
if (lastone != '.') {
data = parseFloat(data);
}
}
return data;
};
$('#result').html(parse(200)); // output 200
$('#result1').html(parse(200.1)); // output 200.1
$('#result2').html(parse(200.10)); // output 200.1
$('#result3').html(parse(200.109)); // output 200.11
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div id="result"></div>
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>
I got some ideas from this post a few months back, but none of the answers here, nor answers from other posts/blogs could handle all the scenarios (e.g. negative numbers and some "lucky numbers" our tester found). In the end, our tester did not find any problem with this method below. Pasting a snippet of my code:
fixPrecision: function (value) {
var me = this,
nan = isNaN(value),
precision = me.decimalPrecision;
if (nan || !value) {
return nan ? '' : value;
} else if (!me.allowDecimals || precision <= 0) {
precision = 0;
}
//[1]
//return parseFloat(Ext.Number.toFixed(parseFloat(value), precision));
precision = precision || 0;
var negMultiplier = value < 0 ? -1 : 1;
//[2]
var numWithExp = parseFloat(value + "e" + precision);
var roundedNum = parseFloat(Math.round(Math.abs(numWithExp)) + 'e-' + precision) * negMultiplier;
return parseFloat(roundedNum.toFixed(precision));
},
I also have code comments (sorry i forgot all the details already)...I'm posting my answer here for future reference:
9.995 * 100 = 999.4999999999999
Whereas 9.995e2 = 999.5
This discrepancy causes Math.round(9.995 * 100) = 999 instead of 1000.
Use e notation instead of multiplying /dividing by Math.Pow(10,precision).
I'm fix the problem the modifier.
Support 2 decimal only.
$(function(){
//input number only.
convertNumberFloatZero(22); // output : 22.00
convertNumberFloatZero(22.5); // output : 22.50
convertNumberFloatZero(22.55); // output : 22.55
convertNumberFloatZero(22.556); // output : 22.56
convertNumberFloatZero(22.555); // output : 22.55
convertNumberFloatZero(22.5541); // output : 22.54
convertNumberFloatZero(22222.5541); // output : 22,222.54
function convertNumberFloatZero(number){
if(!$.isNumeric(number)){
return 'NaN';
}
var numberFloat = number.toFixed(3);
var splitNumber = numberFloat.split(".");
var cNumberFloat = number.toFixed(2);
var cNsplitNumber = cNumberFloat.split(".");
var lastChar = splitNumber[1].substr(splitNumber[1].length - 1);
if(lastChar > 0 && lastChar < 5){
cNsplitNumber[1]--;
}
return Number(splitNumber[0]).toLocaleString('en').concat('.').concat(cNsplitNumber[1]);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
(Math.round((10.2)*100)/100).toFixed(2)
That should yield: 10.20
(Math.round((.05)*100)/100).toFixed(2)
That should yield: 0.05
(Math.round((4.04)*100)/100).toFixed(2)
That should yield: 4.04
etc.
/*Due to all told stuff. You may do 2 things for different purposes:
When showing/printing stuff use this in your alert/innerHtml= contents:
YourRebelNumber.toFixed(2)*/
var aNumber=9242.16;
var YourRebelNumber=aNumber-9000;
alert(YourRebelNumber);
alert(YourRebelNumber.toFixed(2));
/*and when comparing use:
Number(YourRebelNumber.toFixed(2))*/
if(YourRebelNumber==242.16)alert("Not Rounded");
if(Number(YourRebelNumber.toFixed(2))==242.16)alert("Rounded");
/*Number will behave as you want in that moment. After that, it'll return to its defiance.
*/
This is very simple and works just as well as any of the others:
function parseNumber(val, decimalPlaces) {
if (decimalPlaces == null) decimalPlaces = 0
var ret = Number(val).toFixed(decimalPlaces)
return Number(ret)
}
Since toFixed() can only be called on numbers, and unfortunately returns a string, this does all the parsing for you in both directions. You can pass a string or a number, and you get a number back every time! Calling parseNumber(1.49) will give you 1, and parseNumber(1.49,2) will give you 1.50. Just like the best of 'em!
You could also use the .toPrecision() method and some custom code, and always round up to the nth decimal digit regardless the length of int part.
function glbfrmt (number, decimals, seperator) {
return typeof number !== 'number' ? number : number.toPrecision( number.toString().split(seperator)[0].length + decimals);
}
You could also make it a plugin for a better use.
Here's a TypeScript implementation of https://stackoverflow.com/a/21323330/916734. It also dries things up with functions, and allows for a optional digit offset.
export function round(rawValue: number | string, precision = 0, fractionDigitOffset = 0): number | string {
const value = Number(rawValue);
if (isNaN(value)) return rawValue;
precision = Number(precision);
if (precision % 1 !== 0) return NaN;
let [ stringValue, exponent ] = scientificNotationToParts(value);
let shiftExponent = exponentForPrecision(exponent, precision, Shift.Right);
const enlargedValue = toScientificNotation(stringValue, shiftExponent);
const roundedValue = Math.round(enlargedValue);
[ stringValue, exponent ] = scientificNotationToParts(roundedValue);
const precisionWithOffset = precision + fractionDigitOffset;
shiftExponent = exponentForPrecision(exponent, precisionWithOffset, Shift.Left);
return toScientificNotation(stringValue, shiftExponent);
}
enum Shift {
Left = -1,
Right = 1,
}
function scientificNotationToParts(value: number): Array<string> {
const [ stringValue, exponent ] = value.toString().split('e');
return [ stringValue, exponent ];
}
function exponentForPrecision(exponent: string, precision: number, shift: Shift): number {
precision = shift * precision;
return exponent ? (Number(exponent) + precision) : precision;
}
function toScientificNotation(value: string, exponent: number): number {
return Number(`${value}e${exponent}`);
}
fun Any.twoDecimalPlaces(numInDouble: Double): String {
return "%.2f".format(numInDouble)
}
I'm trying to create a javascript function that can take a fraction input string such as '3/2' and convert it to decimal—either as a string '1.5' or number 1.5
function ratio(fraction) {
var fraction = (fraction !== undefined) ? fraction : '1/1',
decimal = ??????????;
return decimal;
});
Is there a way to do this?
Since no one has mentioned it yet there is a quick and dirty solution:
var decimal = eval(fraction);
Which has the perks of correctly evaluating all sorts of mathematical strings.
eval("3/2") // 1.5
eval("6") // 6
eval("6.5/.5") // 13, works with decimals (floats)
eval("12 + 3") // 15, you can add subtract and multiply too
People here will be quick to mention the dangers of using a raw eval but I submit this as the lazy mans answer.
Here is the bare bones minimal code needed to do this:
var a = "3/2";
var split = a.split('/');
var result = parseInt(split[0], 10) / parseInt(split[1], 10);
alert(result); // alerts 1.5
JsFiddle: http://jsfiddle.net/XS4VE/
Things to consider:
division by zero
if the user gives you an integer instead of a fraction, or any other invalid input
rounding issues (like 1/3 for example)
Something like this:
bits = fraction.split("/");
return parseInt(bits[0],10)/parseInt(bits[1],10);
I have a function I use to handle integers, mixed fractions (including unicode vulgar fraction characters), and decimals. Probably needs some polishing but it works for my purpose (recipe ingredient list parsing).
NPM
GitHub
Inputs "2 1/2", "2½", "2 ½", and "2.5" will all return 2.5. Examples:
var numQty = require("numeric-quantity");
numQty("1 1/4") === 1.25; // true
numQty("3 / 4") === 0.75; // true
numQty("¼" ) === 0.25; // true
numQty("2½") === 2.5; // true
numQty("¾") === 0.75; // true
numQty("⅓") === 0.333; // true
numQty("⅔") === 0.667; // true
One thing it doesn't handle is decimals within the fraction, e.g. "2.5 / 5".
I created a nice function to do just that, everything was based off of this question and answers but it will take the string and output the decimal value but will also output whole numbers as well with out errors
https://gist.github.com/drifterz28/6971440
function toDeci(fraction) {
fraction = fraction.toString();
var result,wholeNum=0, frac, deci=0;
if(fraction.search('/') >=0){
if(fraction.search('-') >=0){
wholeNum = fraction.split('-');
frac = wholeNum[1];
wholeNum = parseInt(wholeNum,10);
}else{
frac = fraction;
}
if(fraction.search('/') >=0){
frac = frac.split('/');
deci = parseInt(frac[0], 10) / parseInt(frac[1], 10);
}
result = wholeNum+deci;
}else{
result = fraction
}
return result;
}
/* Testing values / examples */
console.log('1 ',toDeci("1-7/16"));
console.log('2 ',toDeci("5/8"));
console.log('3 ',toDeci("3-3/16"));
console.log('4 ',toDeci("12"));
console.log('5 ',toDeci("12.2"));
Too late, but can be helpful:
You can use Array.prototype.reduce instead of eval
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
ES6
const fractionStrToDecimal = str => str.split('/').reduce((p, c) => p / c);
console.log(fractionStrToDecimal('1/4/2')); // Logs 0.125
console.log(fractionStrToDecimal('3/2')); // Logs 1.5
CJS
function fractionStrToDecimal(str) {
return str.split('/').reduce((p, c) => p / c);
}
console.log(fractionStrToDecimal('1/4')); // Logs 0.25
[EDIT] Removed reducer initial value and now the function works for numerators greater than 1. Thanks, James Furey.
Function (ES6):
function fractionToDecimal(fraction) {
return fraction
.split('/')
.reduce((numerator, denominator, i) =>
numerator / (i ? denominator : 1)
);
}
Function (ES6, condensed):
function fractionToDecimal(f) {
return f.split('/').reduce((n, d, i) => n / (i ? d : 1));
}
Examples:
fractionToDecimal('1/2'); // 0.5
fractionToDecimal('5/2'); // 2.5
fractionToDecimal('1/2/2'); // 0.25
fractionToDecimal('10/5/10'); // 0.2
fractionToDecimal('0/1'); // 0
fractionToDecimal('1/0'); // Infinity
fractionToDecimal('cat/dog'); // NaN
With modern destructuring syntax, the best/safest answer can be simplified to:
const parseFraction = fraction => {
const [numerator, denominator] = fraction.split('/').map(Number);
return numerator / denominator;
}
// example
parseFraction('3/2'); // 1.5
In other words, split the faction by its / symbol, turn both resulting strings into numbers, then return the first number divided by the second ...
... all with only two (very readable) lines of code.
If you don't mind using an external library, math.js offers some useful functions to convert fractions to decimals as well as perform fractional number arithmetic.
console.log(math.number(math.fraction("1/3"))); //returns 0.3333333333333333
console.log(math.fraction("1/3") * 9) //returns 3
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.20.1/math.js"></script>
const fractionStringToNumber = s => s.split("/").map(s => Number(s)).reduce((a, b) => a / b);
console.log(fractionStringToNumber("1/2"));
console.log(fractionStringToNumber("1/3"));
console.log(fractionStringToNumber("3/2"));
console.log(fractionStringToNumber("3/1"));
console.log(fractionStringToNumber("22/7"));
console.log(fractionStringToNumber("355 / 113"));
console.log(fractionStringToNumber("8/4/2"));
console.log(fractionStringToNumber("3")); // => 3, not "3"
From a readability, step through debugging perspective, this may be easier to follow:
// i.e. '1/2' -> .5
// Invalid input returns 0 so impact on upstream callers are less likely to be impacted
function fractionToNumber(fraction = '') {
const fractionParts = fraction.split('/');
const numerator = fractionParts[0] || '0';
const denominator = fractionParts[1] || '1';
const radix = 10;
const number = parseInt(numerator, radix) / parseInt(denominator, radix);
const result = number || 0;
return result;
}
To convert a fraction to a decimal, just divide the top number by the bottom number. 5 divided by 3 would be 5/3 or 1.67. Much like:
function decimal(top,bottom) {
return (top/bottom)
}
Hope this helps, haha
It works with eval() method but you can use parseFloat method. I think it is better!
Unfortunately it will work only with that kind of values - "12.2" not with "5/8", but since you can handle with calculation I think this is good approach!
If you want to use the result as a fraction and not just get the answer from the string, a library like https://github.com/infusion/Fraction.js would do the job quite well.
var f = new Fraction("3/2");
console.log(f.toString()); // Returns string "1.5"
console.log(f.valueOf()); // Returns number 1.5
var g = new Fraction(6.5).div(.5);
console.log(f.toString()); // Returns string "13"
Also a bit late to the party, but an alternative to eval() with less security issues (according to MDN at least) is the Function() factory.
var fraction = "3/2";
console.log( Function("return (" + fraction + ");")() );
This would output the result "1.5" in the console.
Also as a side note: Mixed fractions like 1 1/2 will not work with neither eval() nor the solution with Function() as written as they both stumble on the space.
safer eval() according to MDN
const safeEval = (str) => {
return Function('"use strict";return (' + str + ")")();
}
safeEval("1 1/2") // 1.5
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#Do_not_ever_use_eval!
This too will work:
let y = "2.9/59"
let a = y.split('')
let b = a.splice(a.indexOf("/"))
console.log(parseFloat(a.join('')))
a = parseFloat(a.join(''))
console.log(b)
let c = parseFloat(b.slice(1).join(''))
let d = a/c
console.log(d) // Answer for y fraction
I developed a function to convert a value using a factor that may be passed as a fraction of integers or decimals. The user input and conversion factor might not be in the correct format, so it checks for the original value to be a number, as well as that the conversion can be converted to a fraction assuming that /number means 1/number, or there are a numerator and a denominator in the format number/number.
/**
* Convert value using conversion factor
* #param {float} value - number to convert
* #param {string} conversion - factor
* #return {float} converted value
*/
function convertNumber(value, conversion) {
try {
let numberValue = eval(value);
if (isNaN(numberValue)) {
throw value + " is not a number.";
}
let fraction = conversion.toString();
let divider = fraction.indexOf("/");
let upper = 1;
let denominator = 1;
if (divider == -1) {
upper = eval(fraction);
} else {
let split = fraction.split("/");
if (split.length > 2) {
throw fraction + " cannot be evaluated to a fraction.";
} else {
denominator = eval(split[1]);
if (divider > 0) {
upper = eval(split[0]);
}
}
}
let factor = upper/denominator;
if (isNaN(factor)) {
throw fraction + " cannot be converted to a factor.";
}
let result = numberValue * factor;
if (isNaN(result)) {
throw numberValue + " * " + factor + " is not a number.";
}
return result
} catch (err) {
let message = "Unable to convert '" + value + "' using '" + conversion + "'. " + err;
throw message;
}
}
You can use eval() with regex to implement a secure method to calculate fraction
var input = "1/2";
return input.match(/^[0-9\/\.]+$/) != null ? eval(input) : "invalid number";
I have a question regarding toFixed() function. If I have a float e.g. - 3.123123423 and 0. How can I output it to input box with toFixed(2) so the inputbox values would be 3.12 and 0. I mean if the value is integer I want output it without trailing .00 :)
As there is no difference between integers and floats in JavaScript, here is my quick'n'dirty approach:
theNumber.toFixed(2).replace(".00", "");
Or something generic:
myToFixed = function (n, digits) {
digits = digits || 0;
return n.toFixed(digits).replace(new RegExp("\\.0{" + digits + "}"), "");
}
myToFixed(32.1212, 2) --> "32.12"
myToFixed(32.1212, 0) --> "32"
myToFixed(32, 2) --> "32"
myToFixed(32.1, 2) --> "32.10"
You don't need Math.round():
var toFixed = function(val, n) {
var result = val.toFixed(n);
if (result == val)
return val.toString();
return result;
}
toFixed(3.123, 2) --> "3.12"
toFixed(3, 2) --> "3"
function toFixed0d(x, d)
{
if(Math.round(x) == x)
{
return x.toString();
}else
{
return x.toFixed(d);
}
}
toFixed0d(3.123123423, 2) = "3.12"
toFixed0d(0, 2) = "0"
Note that toFixed() is broken in IE and generally not to be relied on. Annoying but accurately-rounded replacement functions given there.
Number.toFixed produces some mathematically bizarre results and gives you the fractional digits you asked for, whether you need them or not.
Math.round is mathematically correct, but doesn't allow you to specify a precision.
Here's a function that's both mathematically correct (disregarding floating point errors) and that gives you what you want.
var roundToPlusInfinity = function(n, fd) {
var scale = Math.pow(10, fd),
rounded = fd ? Math.floor((n * scale + 0.5)) / scale :
Math.round(n);
return rounded.toString();
};
The algorithm is: scale up so that the digits you want are to the left of the decimal point, add .5 (so that >= .5 in the first insignificant place causes an increment of the integer portion), truncate (not round!) and scale back down. There's the potential for floating point errors to creep in, but it's a sight better than the wretched toFixed function.
Testing it out:
roundToPlusInfinity(5.53335, 4); // "5.3334"
roundToPlusInfinity(-9999.95, 1); // "-9999.9"
roundToPlusInfinity(3.00015, 3); // "3"
Because of the possibility of floating point error, the scale down might give a result like "3.00000000001", which is annoying. Something like this should take care of it.
var trimFraction = function(s, fd) {
var splitPoint = s.indexOf('.');
if (splitPoint === -1) {
return s;
}
var f = s.substring(splitPoint + 1, s.length),
i = s.substring(0, splitPoint);
if (f.length > fd) {
f = f.substring(0, fd).replace(/0+$/, "");
}
if (f) {
return i + '.' + f;
}
return i;
};
trimFraction("3.1000000001", 2); // "3.1"
You haven't made clear the rounding algorithm you want. Round towards plus infinity is the rounding you learnt at school where you round >= .5 up (i.e. towards positive infinity). I believe that in accounting, the correct rounding algorithm (outside Switzerland and Argentina at least) is away from zero. Simple:
var roundAwayFromZero = function(n, fd) {
var ret = roundToPlusInfinity(Math.abs(n), fd);
return (n < 0) ? '-' + ret : ret;
};
roundAwayFromZero(-9999.95, 1); // "-10000"
If the results are for human presentation, Intl.NumberFormat is a possibility, since you can specify both the minimum and maximum number of fractional digits. At the time of writing it's not exactly widely supported and, assuming that Chrome implements the specification correctly, uses the same impenetrable and plain wrong truncating algorithm as toFixed. Interestingly, the "currency" style uses roundAwayFromZero (or round to a half if the currency code is "CHF", which is a nice touch).
Here is a function I came up with after thinking about this same problem for a little while:
function toFixed (number, n) {
return parseFloat(number.toFixed(n));
}
As per this question, this function will return as follows:
toFixed(3.123123423, 2);
> 3.12
toFixed(0, 2);
> 0
toFixed(3.1, 2);
> 3.1
toFixed(3.005, 2);
> 3
toFixed(3.005, 3);
> 3.005
toFixed(3.0500, 4);
> 3.05
Note that the toFixed method of the JavaScript's Number object actually returns a String. The above toFixed function will return a Number. If you'd rather have a String then use the following instead:
function toFixed (number, n) {
return parseFloat(number.toFixed(n)).toString();
}
In JavaScript, when converting from a float to a string, how can I get just 2 digits after the decimal point? For example, 0.34 instead of 0.3445434.
There are functions to round numbers. For example:
var x = 5.0364342423;
print(x.toFixed(2));
will print 5.04.
EDIT:
Fiddle
var result = Math.round(original*100)/100;
The specifics, in case the code isn't self-explanatory.
edit: ...or just use toFixed, as proposed by Tim Büthe. Forgot that one, thanks (and an upvote) for reminder :)
Be careful when using toFixed():
First, rounding the number is done using the binary representation of the number, which might lead to unexpected behaviour. For example
(0.595).toFixed(2) === '0.59'
instead of '0.6'.
Second, there's an IE bug with toFixed(). In IE (at least up to version 7, didn't check IE8), the following holds true:
(0.9).toFixed(0) === '0'
It might be a good idea to follow kkyy's suggestion or to use a custom toFixed() function, eg
function toFixed(value, precision) {
var power = Math.pow(10, precision || 0);
return String(Math.round(value * power) / power);
}
One more problem to be aware of, is that toFixed() can produce unnecessary zeros at the end of the number.
For example:
var x=(23-7.37)
x
15.629999999999999
x.toFixed(6)
"15.630000"
The idea is to clean up the output using a RegExp:
function humanize(x){
return x.toFixed(6).replace(/\.?0*$/,'');
}
The RegExp matches the trailing zeros (and optionally the decimal point) to make sure it looks good for integers as well.
humanize(23-7.37)
"15.63"
humanize(1200)
"1200"
humanize(1200.03)
"1200.03"
humanize(3/4)
"0.75"
humanize(4/3)
"1.333333"
var x = 0.3445434
x = Math.round (x*100) / 100 // this will make nice rounding
The key here I guess is to round up correctly first, then you can convert it to String.
function roundOf(n, p) {
const n1 = n * Math.pow(10, p + 1);
const n2 = Math.floor(n1 / 10);
if (n1 >= (n2 * 10 + 5)) {
return (n2 + 1) / Math.pow(10, p);
}
return n2 / Math.pow(10, p);
}
// All edge cases listed in this thread
roundOf(95.345, 2); // 95.35
roundOf(95.344, 2); // 95.34
roundOf(5.0364342423, 2); // 5.04
roundOf(0.595, 2); // 0.60
roundOf(0.335, 2); // 0.34
roundOf(0.345, 2); // 0.35
roundOf(551.175, 2); // 551.18
roundOf(0.3445434, 2); // 0.34
Now you can safely format this value with toFixed(p).
So with your specific case:
roundOf(0.3445434, 2).toFixed(2); // 0.34
There is a problem with all those solutions floating around using multipliers. Both kkyy and Christoph's solutions are wrong unfortunately.
Please test your code for number 551.175 with 2 decimal places - it will round to 551.17 while it should be 551.18 ! But if you test for ex. 451.175 it will be ok - 451.18. So it's difficult to spot this error at a first glance.
The problem is with multiplying: try 551.175 * 100 = 55117.49999999999 (ups!)
So my idea is to treat it with toFixed() before using Math.round();
function roundFix(number, precision)
{
var multi = Math.pow(10, precision);
return Math.round( (number * multi).toFixed(precision + 1) ) / multi;
}
If you want the string without round you can use this RegEx (maybe is not the most efficient way... but is really easy)
(2.34567778).toString().match(/\d+\.\d{2}/)[0]
// '2.34'
function trimNumber(num, len) {
const modulu_one = 1;
const start_numbers_float=2;
var int_part = Math.trunc(num);
var float_part = String(num % modulu_one);
float_part = float_part.slice(start_numbers_float, start_numbers_float+len);
return int_part+'.'+float_part;
}
There is no way to avoid inconsistent rounding for prices with x.xx5 as actual value using either multiplication or division. If you need to calculate correct prices client-side you should keep all amounts in cents. This is due to the nature of the internal representation of numeric values in JavaScript. Notice that Excel suffers from the same problems so most people wouldn't notice the small errors caused by this phenomen. However errors may accumulate whenever you add up a lot of calculated values, there is a whole theory around this involving the order of calculations and other methods to minimize the error in the final result. To emphasize on the problems with decimal values, please note that 0.1 + 0.2 is not exactly equal to 0.3 in JavaScript, while 1 + 2 is equal to 3.
Maybe you'll also want decimal separator? Here is a function I just made:
function formatFloat(num,casasDec,sepDecimal,sepMilhar) {
if (num < 0)
{
num = -num;
sinal = -1;
} else
sinal = 1;
var resposta = "";
var part = "";
if (num != Math.floor(num)) // decimal values present
{
part = Math.round((num-Math.floor(num))*Math.pow(10,casasDec)).toString(); // transforms decimal part into integer (rounded)
while (part.length < casasDec)
part = '0'+part;
if (casasDec > 0)
{
resposta = sepDecimal+part;
num = Math.floor(num);
} else
num = Math.round(num);
} // end of decimal part
while (num > 0) // integer part
{
part = (num - Math.floor(num/1000)*1000).toString(); // part = three less significant digits
num = Math.floor(num/1000);
if (num > 0)
while (part.length < 3) // 123.023.123 if sepMilhar = '.'
part = '0'+part; // 023
resposta = part+resposta;
if (num > 0)
resposta = sepMilhar+resposta;
}
if (sinal < 0)
resposta = '-'+resposta;
return resposta;
}
/** don't spend 5 minutes, use my code **/
function prettyFloat(x,nbDec) {
if (!nbDec) nbDec = 100;
var a = Math.abs(x);
var e = Math.floor(a);
var d = Math.round((a-e)*nbDec); if (d == nbDec) { d=0; e++; }
var signStr = (x<0) ? "-" : " ";
var decStr = d.toString(); var tmp = 10; while(tmp<nbDec && d*tmp < nbDec) {decStr = "0"+decStr; tmp*=10;}
var eStr = e.toString();
return signStr+eStr+"."+decStr;
}
prettyFloat(0); // "0.00"
prettyFloat(-1); // "-1.00"
prettyFloat(-0.999); // "-1.00"
prettyFloat(0.5); // "0.50"
I use this code to format floats. It is based on toPrecision() but it strips unnecessary zeros. I would welcome suggestions for how to simplify the regex.
function round(x, n) {
var exp = Math.pow(10, n);
return Math.floor(x*exp + 0.5)/exp;
}
Usage example:
function test(x, n, d) {
var rounded = rnd(x, d);
var result = rounded.toPrecision(n);
result = result.replace(/\.?0*$/, '');
result = result.replace(/\.?0*e/, 'e');
result = result.replace('e+', 'e');
return result;
}
document.write(test(1.2000e45, 3, 2) + '=' + '1.2e45' + '<br>');
document.write(test(1.2000e+45, 3, 2) + '=' + '1.2e45' + '<br>');
document.write(test(1.2340e45, 3, 2) + '=' + '1.23e45' + '<br>');
document.write(test(1.2350e45, 3, 2) + '=' + '1.24e45' + '<br>');
document.write(test(1.0000, 3, 2) + '=' + '1' + '<br>');
document.write(test(1.0100, 3, 2) + '=' + '1.01' + '<br>');
document.write(test(1.2340, 4, 2) + '=' + '1.23' + '<br>');
document.write(test(1.2350, 4, 2) + '=' + '1.24' + '<br>');
countDecimals = value => {
if (Math.floor(value) === value) return 0;
let stringValue = value.toString().split(".")[1];
if (stringValue) {
return value.toString().split(".")[1].length
? value.toString().split(".")[1].length
: 0;
} else {
return 0;
}
};
formatNumber=(ans)=>{
let decimalPlaces = this.countDecimals(ans);
ans = 1 * ans;
if (decimalPlaces !== 0) {
let onePlusAns = ans + 1;
let decimalOnePlus = this.countDecimals(onePlusAns);
if (decimalOnePlus < decimalPlaces) {
ans = ans.toFixed(decimalPlaces - 1).replace(/\.?0*$/, "");
} else {
let tenMulAns = ans * 10;
let decimalTenMul = this.countDecimals(tenMulAns);
if (decimalTenMul + 1 < decimalPlaces) {
ans = ans.toFixed(decimalPlaces - 1).replace(/\.?0*$/, "");
}
}
}
}
I just add 1 to the value and count the decimal digits present in the original value and the added value. If I find the decimal digits after adding one less than the original decimal digits, I just call the toFixed() with (original decimals - 1). I also check by multiplying the original value by 10 and follow the same logic in case adding one doesn't reduce redundant decimal places.
A simple workaround to handle floating-point number rounding in JS. Works in most cases I tried.
How do you convert decimal values to their hexadecimal equivalent in JavaScript?
Convert a number to a hexadecimal string with:
hexString = yourNumber.toString(16);
And reverse the process with:
yourNumber = parseInt(hexString, 16);
If you need to handle things like bit fields or 32-bit colors, then you need to deal with signed numbers. The JavaScript function toString(16) will return a negative hexadecimal number which is usually not what you want. This function does some crazy addition to make it a positive number.
function decimalToHexString(number)
{
if (number < 0)
{
number = 0xFFFFFFFF + number + 1;
}
return number.toString(16).toUpperCase();
}
console.log(decimalToHexString(27));
console.log(decimalToHexString(48.6));
The code below will convert the decimal value d to hexadecimal. It also allows you to add padding to the hexadecimal result. So 0 will become 00 by default.
function decimalToHex(d, padding) {
var hex = Number(d).toString(16);
padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
while (hex.length < padding) {
hex = "0" + hex;
}
return hex;
}
function toHex(d) {
return ("0"+(Number(d).toString(16))).slice(-2).toUpperCase()
}
For completeness, if you want the two's-complement hexadecimal representation of a negative number, you can use the zero-fill-right shift >>> operator. For instance:
> (-1).toString(16)
"-1"
> ((-2)>>>0).toString(16)
"fffffffe"
There is however one limitation: JavaScript bitwise operators treat their operands as a sequence of 32 bits, that is, you get the 32-bits two's complement.
With padding:
function dec2hex(i) {
return (i+0x10000).toString(16).substr(-4).toUpperCase();
}
The accepted answer did not take into account single digit returned hexadecimal codes. This is easily adjusted by:
function numHex(s)
{
var a = s.toString(16);
if ((a.length % 2) > 0) {
a = "0" + a;
}
return a;
}
and
function strHex(s)
{
var a = "";
for (var i=0; i<s.length; i++) {
a = a + numHex(s.charCodeAt(i));
}
return a;
}
I believe the above answers have been posted numerous times by others in one form or another. I wrap these in a toHex() function like so:
function toHex(s)
{
var re = new RegExp(/^\s*(\+|-)?((\d+(\.\d+)?)|(\.\d+))\s*$/);
if (re.test(s)) {
return '#' + strHex( s.toString());
}
else {
return 'A' + strHex(s);
}
}
Note that the numeric regular expression came from 10+ Useful JavaScript Regular Expression Functions to improve your web applications efficiency.
Update: After testing this thing several times I found an error (double quotes in the RegExp), so I fixed that. HOWEVER! After quite a bit of testing and having read the post by almaz - I realized I could not get negative numbers to work.
Further - I did some reading up on this and since all JavaScript numbers are stored as 64 bit words no matter what - I tried modifying the numHex code to get the 64 bit word. But it turns out you can not do that. If you put "3.14159265" AS A NUMBER into a variable - all you will be able to get is the "3", because the fractional portion is only accessible by multiplying the number by ten(IE:10.0) repeatedly. Or to put that another way - the hexadecimal value of 0xF causes the floating point value to be translated into an integer before it is ANDed which removes everything behind the period. Rather than taking the value as a whole (i.e.: 3.14159265) and ANDing the floating point value against the 0xF value.
So the best thing to do, in this case, is to convert the 3.14159265 into a string and then just convert the string. Because of the above, it also makes it easy to convert negative numbers because the minus sign just becomes 0x26 on the front of the value.
So what I did was on determining that the variable contains a number - just convert it to a string and convert the string. This means to everyone that on the server side you will need to unhex the incoming string and then to determine the incoming information is numeric. You can do that easily by just adding a "#" to the front of numbers and "A" to the front of a character string coming back. See the toHex() function.
Have fun!
After another year and a lot of thinking, I decided that the "toHex" function (and I also have a "fromHex" function) really needed to be revamped. The whole question was "How can I do this more efficiently?" I decided that a to/from hexadecimal function should not care if something is a fractional part but at the same time it should ensure that fractional parts are included in the string.
So then the question became, "How do you know you are working with a hexadecimal string?". The answer is simple. Use the standard pre-string information that is already recognized around the world.
In other words - use "0x". So now my toHex function looks to see if that is already there and if it is - it just returns the string that was sent to it. Otherwise, it converts the string, number, whatever. Here is the revised toHex function:
/////////////////////////////////////////////////////////////////////////////
// toHex(). Convert an ASCII string to hexadecimal.
/////////////////////////////////////////////////////////////////////////////
toHex(s)
{
if (s.substr(0,2).toLowerCase() == "0x") {
return s;
}
var l = "0123456789ABCDEF";
var o = "";
if (typeof s != "string") {
s = s.toString();
}
for (var i=0; i<s.length; i++) {
var c = s.charCodeAt(i);
o = o + l.substr((c>>4),1) + l.substr((c & 0x0f),1);
}
return "0x" + o;
}
This is a very fast function that takes into account single digits, floating point numbers, and even checks to see if the person is sending a hex value over to be hexed again. It only uses four function calls and only two of those are in the loop. To un-hex the values you use:
/////////////////////////////////////////////////////////////////////////////
// fromHex(). Convert a hex string to ASCII text.
/////////////////////////////////////////////////////////////////////////////
fromHex(s)
{
var start = 0;
var o = "";
if (s.substr(0,2).toLowerCase() == "0x") {
start = 2;
}
if (typeof s != "string") {
s = s.toString();
}
for (var i=start; i<s.length; i+=2) {
var c = s.substr(i, 2);
o = o + String.fromCharCode(parseInt(c, 16));
}
return o;
}
Like the toHex() function, the fromHex() function first looks for the "0x" and then it translates the incoming information into a string if it isn't already a string. I don't know how it wouldn't be a string - but just in case - I check. The function then goes through, grabbing two characters and translating those in to ASCII characters. If you want it to translate Unicode, you will need to change the loop to going by four(4) characters at a time. But then you also need to ensure that the string is NOT divisible by four. If it is - then it is a standard hexadecimal string. (Remember the string has "0x" on the front of it.)
A simple test script to show that -3.14159265, when converted to a string, is still -3.14159265.
<?php
echo <<<EOD
<html>
<head><title>Test</title>
<script>
var a = -3.14159265;
alert( "A = " + a );
var b = a.toString();
alert( "B = " + b );
</script>
</head>
<body>
</body>
</html>
EOD;
?>
Because of how JavaScript works in respect to the toString() function, all of those problems can be eliminated which before were causing problems. Now all strings and numbers can be converted easily. Further, such things as objects will cause an error to be generated by JavaScript itself. I believe this is about as good as it gets. The only improvement left is for W3C to just include a toHex() and fromHex() function in JavaScript.
Without the loop:
function decimalToHex(d) {
var hex = Number(d).toString(16);
hex = "000000".substr(0, 6 - hex.length) + hex;
return hex;
}
// Or "#000000".substr(0, 7 - hex.length) + hex;
// Or whatever
// *Thanks to MSDN
Also isn't it better not to use loop tests that have to be evaluated?
For example, instead of:
for (var i = 0; i < hex.length; i++){}
have
for (var i = 0, var j = hex.length; i < j; i++){}
Combining some of these good ideas for an RGB-value-to-hexadecimal function (add the # elsewhere for HTML/CSS):
function rgb2hex(r,g,b) {
if (g !== undefined)
return Number(0x1000000 + r*0x10000 + g*0x100 + b).toString(16).substring(1);
else
return Number(0x1000000 + r[0]*0x10000 + r[1]*0x100 + r[2]).toString(16).substring(1);
}
Constrained/padded to a set number of characters:
function decimalToHex(decimal, chars) {
return (decimal + Math.pow(16, chars)).toString(16).slice(-chars).toUpperCase();
}
For anyone interested, here's a JSFiddle comparing most of the answers given to this question.
And here's the method I ended up going with:
function decToHex(dec) {
return (dec + Math.pow(16, 6)).toString(16).substr(-6)
}
Also, bear in mind that if you're looking to convert from decimal to hex for use in CSS as a color data type, you might instead prefer to extract the RGB values from the decimal and use rgb().
For example (JSFiddle):
let c = 4210330 // your color in decimal format
let rgb = [(c & 0xff0000) >> 16, (c & 0x00ff00) >> 8, (c & 0x0000ff)]
// Vanilla JS:
document.getElementById('some-element').style.color = 'rgb(' + rgb + ')'
// jQuery:
$('#some-element').css('color', 'rgb(' + rgb + ')')
This sets #some-element's CSS color property to rgb(64, 62, 154).
var number = 3200;
var hexString = number.toString(16);
The 16 is the radix and there are 16 values in a hexadecimal number :-)
function dec2hex(i)
{
var result = "0000";
if (i >= 0 && i <= 15) { result = "000" + i.toString(16); }
else if (i >= 16 && i <= 255) { result = "00" + i.toString(16); }
else if (i >= 256 && i <= 4095) { result = "0" + i.toString(16); }
else if (i >= 4096 && i <= 65535) { result = i.toString(16); }
return result
}
If you want to convert a number to a hexadecimal representation of an RGBA color value, I've found this to be the most useful combination of several tips from here:
function toHexString(n) {
if(n < 0) {
n = 0xFFFFFFFF + n + 1;
}
return "0x" + ("00000000" + n.toString(16).toUpperCase()).substr(-8);
}
AFAIK comment 57807 is wrong and should be something like:
var hex = Number(d).toString(16);
instead of
var hex = parseInt(d, 16);
function decimalToHex(d, padding) {
var hex = Number(d).toString(16);
padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
while (hex.length < padding) {
hex = "0" + hex;
}
return hex;
}
And if the number is negative?
Here is my version.
function hexdec (hex_string) {
hex_string=((hex_string.charAt(1)!='X' && hex_string.charAt(1)!='x')?hex_string='0X'+hex_string : hex_string);
hex_string=(hex_string.charAt(2)<8 ? hex_string =hex_string-0x00000000 : hex_string=hex_string-0xFFFFFFFF-1);
return parseInt(hex_string, 10);
}
As the accepted answer states, the easiest way to convert from decimal to hexadecimal is var hex = dec.toString(16). However, you may prefer to add a string conversion, as it ensures that string representations like "12".toString(16) work correctly.
// Avoids a hard-to-track-down bug by returning `c` instead of `12`
(+"12").toString(16);
To reverse the process you may also use the solution below, as it is even shorter.
var dec = +("0x" + hex);
It seems to be slower in Google Chrome and Firefox, but is significantly faster in Opera. See http://jsperf.com/hex-to-dec.
I'm doing conversion to hex string in a pretty large loop, so I tried several techniques in order to find the fastest one. My requirements were to have a fixed-length string as a result, and encode negative values properly (-1 => ff..f).
Simple .toString(16) didn't work for me since I needed negative values to be properly encoded. The following code is the quickest I've tested so far on 1-2 byte values (note that symbols defines the number of output symbols you want to get, that is for 4-byte integer it should be equal to 8):
var hex = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
function getHexRepresentation(num, symbols) {
var result = '';
while (symbols--) {
result = hex[num & 0xF] + result;
num >>= 4;
}
return result;
}
It performs faster than .toString(16) on 1-2 byte numbers and slower on larger numbers (when symbols >= 6), but still should outperform methods that encode negative values properly.
Converting hex color numbers to hex color strings:
A simple solution with toString and ES6 padStart for converting hex color numbers to hex color strings.
const string = `#${color.toString(16).padStart(6, '0')}`;
For example:
0x000000 will become #000000
0xFFFFFF will become #FFFFFF
Check this example in a fiddle here
How to convert decimal to hexadecimal in JavaScript
I wasn't able to find a brutally clean/simple decimal to hexadecimal conversion that didn't involve a mess of functions and arrays ... so I had to make this for myself.
function DecToHex(decimal) { // Data (decimal)
length = -1; // Base string length
string = ''; // Source 'string'
characters = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' ]; // character array
do { // Grab each nibble in reverse order because JavaScript has no unsigned left shift
string += characters[decimal & 0xF]; // Mask byte, get that character
++length; // Increment to length of string
} while (decimal >>>= 4); // For next character shift right 4 bits, or break on 0
decimal += 'x'; // Convert that 0 into a hex prefix string -> '0x'
do
decimal += string[length];
while (length--); // Flip string forwards, with the prefixed '0x'
return (decimal); // return (hexadecimal);
}
/* Original: */
D = 3678; // Data (decimal)
C = 0xF; // Check
A = D; // Accumulate
B = -1; // Base string length
S = ''; // Source 'string'
H = '0x'; // Destination 'string'
do {
++B;
A& = C;
switch(A) {
case 0xA: A='A'
break;
case 0xB: A='B'
break;
case 0xC: A='C'
break;
case 0xD: A='D'
break;
case 0xE: A='E'
break;
case 0xF: A='F'
break;
A = (A);
}
S += A;
D >>>= 0x04;
A = D;
} while(D)
do
H += S[B];
while (B--)
S = B = A = C = D; // Zero out variables
alert(H); // H: holds hexadecimal equivalent
You can do something like this in ECMAScript 6:
const toHex = num => (num).toString(16).toUpperCase();
If you are looking for converting Large integers i.e. Numbers greater than Number.MAX_SAFE_INTEGER -- 9007199254740991, then you can use the following code
const hugeNumber = "9007199254740991873839" // Make sure its in String
const hexOfHugeNumber = BigInt(hugeNumber).toString(16);
console.log(hexOfHugeNumber)
To sum it all up;
function toHex(i, pad) {
if (typeof(pad) === 'undefined' || pad === null) {
pad = 2;
}
var strToParse = i.toString(16);
while (strToParse.length < pad) {
strToParse = "0" + strToParse;
}
var finalVal = parseInt(strToParse, 16);
if ( finalVal < 0 ) {
finalVal = 0xFFFFFFFF + finalVal + 1;
}
return finalVal;
}
However, if you don't need to convert it back to an integer at the end (i.e. for colors), then just making sure the values aren't negative should suffice.
I haven't found a clear answer, without checks if it is negative or positive, that uses two's complement (negative numbers included). For that, I show my solution to one byte:
((0xFF + number +1) & 0x0FF).toString(16);
You can use this instruction to any number bytes, only you add FF in respective places. For example, to two bytes:
((0xFFFF + number +1) & 0x0FFFF).toString(16);
If you want cast an array integer to string hexadecimal:
s = "";
for(var i = 0; i < arrayNumber.length; ++i) {
s += ((0xFF + arrayNumber[i] +1) & 0x0FF).toString(16);
}
In case you're looking to convert to a 'full' JavaScript or CSS representation, you can use something like:
numToHex = function(num) {
var r=((0xff0000&num)>>16).toString(16),
g=((0x00ff00&num)>>8).toString(16),
b=(0x0000ff&num).toString(16);
if (r.length==1) { r = '0'+r; }
if (g.length==1) { g = '0'+g; }
if (b.length==1) { b = '0'+b; }
return '0x'+r+g+b; // ('#' instead of'0x' for CSS)
};
var dec = 5974678;
console.log( numToHex(dec) ); // 0x5b2a96
This is based on Prestaul and Tod's solutions. However, this is a generalisation that accounts for varying size of a variable (e.g. Parsing signed value from a microcontroller serial log).
function decimalToPaddedHexString(number, bitsize)
{
let byteCount = Math.ceil(bitsize/8);
let maxBinValue = Math.pow(2, bitsize)-1;
/* In node.js this function fails for bitsize above 32bits */
if (bitsize > 32)
throw "number above maximum value";
/* Conversion to unsigned form based on */
if (number < 0)
number = maxBinValue + number + 1;
return "0x"+(number >>> 0).toString(16).toUpperCase().padStart(byteCount*2, '0');
}
Test script:
for (let n = 0 ; n < 64 ; n++ ) {
let s=decimalToPaddedHexString(-1, n);
console.log(`decimalToPaddedHexString(-1,${(n+"").padStart(2)}) = ${s.padStart(10)} = ${("0b"+parseInt(s).toString(2)).padStart(34)}`);
}
Test results:
decimalToPaddedHexString(-1, 0) = 0x0 = 0b0
decimalToPaddedHexString(-1, 1) = 0x01 = 0b1
decimalToPaddedHexString(-1, 2) = 0x03 = 0b11
decimalToPaddedHexString(-1, 3) = 0x07 = 0b111
decimalToPaddedHexString(-1, 4) = 0x0F = 0b1111
decimalToPaddedHexString(-1, 5) = 0x1F = 0b11111
decimalToPaddedHexString(-1, 6) = 0x3F = 0b111111
decimalToPaddedHexString(-1, 7) = 0x7F = 0b1111111
decimalToPaddedHexString(-1, 8) = 0xFF = 0b11111111
decimalToPaddedHexString(-1, 9) = 0x01FF = 0b111111111
decimalToPaddedHexString(-1,10) = 0x03FF = 0b1111111111
decimalToPaddedHexString(-1,11) = 0x07FF = 0b11111111111
decimalToPaddedHexString(-1,12) = 0x0FFF = 0b111111111111
decimalToPaddedHexString(-1,13) = 0x1FFF = 0b1111111111111
decimalToPaddedHexString(-1,14) = 0x3FFF = 0b11111111111111
decimalToPaddedHexString(-1,15) = 0x7FFF = 0b111111111111111
decimalToPaddedHexString(-1,16) = 0xFFFF = 0b1111111111111111
decimalToPaddedHexString(-1,17) = 0x01FFFF = 0b11111111111111111
decimalToPaddedHexString(-1,18) = 0x03FFFF = 0b111111111111111111
decimalToPaddedHexString(-1,19) = 0x07FFFF = 0b1111111111111111111
decimalToPaddedHexString(-1,20) = 0x0FFFFF = 0b11111111111111111111
decimalToPaddedHexString(-1,21) = 0x1FFFFF = 0b111111111111111111111
decimalToPaddedHexString(-1,22) = 0x3FFFFF = 0b1111111111111111111111
decimalToPaddedHexString(-1,23) = 0x7FFFFF = 0b11111111111111111111111
decimalToPaddedHexString(-1,24) = 0xFFFFFF = 0b111111111111111111111111
decimalToPaddedHexString(-1,25) = 0x01FFFFFF = 0b1111111111111111111111111
decimalToPaddedHexString(-1,26) = 0x03FFFFFF = 0b11111111111111111111111111
decimalToPaddedHexString(-1,27) = 0x07FFFFFF = 0b111111111111111111111111111
decimalToPaddedHexString(-1,28) = 0x0FFFFFFF = 0b1111111111111111111111111111
decimalToPaddedHexString(-1,29) = 0x1FFFFFFF = 0b11111111111111111111111111111
decimalToPaddedHexString(-1,30) = 0x3FFFFFFF = 0b111111111111111111111111111111
decimalToPaddedHexString(-1,31) = 0x7FFFFFFF = 0b1111111111111111111111111111111
decimalToPaddedHexString(-1,32) = 0xFFFFFFFF = 0b11111111111111111111111111111111
Thrown: 'number above maximum value'
Note: Not too sure why it fails above 32 bitsize
rgb(255, 255, 255) // returns FFFFFF
rgb(255, 255, 300) // returns FFFFFF
rgb(0,0,0) // returns 000000
rgb(148, 0, 211) // returns 9400D3
function rgb(...values){
return values.reduce((acc, cur) => {
let val = cur >= 255 ? 'ff' : cur <= 0 ? '00' : Number(cur).toString(16);
return acc + (val.length === 1 ? '0'+val : val);
}, '').toUpperCase();
}
Arbitrary precision
This solution take on input decimal string, and return hex string. A decimal fractions are supported. Algorithm
split number to sign (s), integer part (i) and fractional part (f) e.g for -123.75 we have s=true, i=123, f=75
integer part to hex:
if i='0' stop
get modulo: m=i%16 (in arbitrary precision)
convert m to hex digit and put to result string
for next step calc integer part i=i/16 (in arbitrary precision)
fractional part
count fractional digits n
multiply k=f*16 (in arbitrary precision)
split k to right part with n digits and put them to f, and left part with rest of digits and put them to d
convert d to hex and add to result.
finish when number of result fractional digits is enough
// #param decStr - string with non-negative integer
// #param divisor - positive integer
function dec2HexArbitrary(decStr, fracDigits=0) {
// Helper: divide arbitrary precision number by js number
// #param decStr - string with non-negative integer
// #param divisor - positive integer
function arbDivision(decStr, divisor)
{
// algorithm https://www.geeksforgeeks.org/divide-large-number-represented-string/
let ans='';
let idx = 0;
let temp = +decStr[idx];
while (temp < divisor) temp = temp * 10 + +decStr[++idx];
while (decStr.length > idx) {
ans += (temp / divisor)|0 ;
temp = (temp % divisor) * 10 + +decStr[++idx];
}
if (ans.length == 0) return "0";
return ans;
}
// Helper: calc module of arbitrary precision number
// #param decStr - string with non-negative integer
// #param mod - positive integer
function arbMod(decStr, mod) {
// algorithm https://www.geeksforgeeks.org/how-to-compute-mod-of-a-big-number/
let res = 0;
for (let i = 0; i < decStr.length; i++)
res = (res * 10 + +decStr[i]) % mod;
return res;
}
// Helper: multiply arbitrary precision integer by js number
// #param decStr - string with non-negative integer
// #param mult - positive integer
function arbMultiply(decStr, mult) {
let r='';
let m=0;
for (let i = decStr.length-1; i >=0 ; i--) {
let n = m+mult*(+decStr[i]);
r= (i ? n%10 : n) + r
m= n/10|0;
}
return r;
}
// dec2hex algorithm starts here
let h= '0123456789abcdef'; // hex 'alphabet'
let m= decStr.match(/-?(.*?)\.(.*)?/) || decStr.match(/-?(.*)/); // separate sign,integer,ractional
let i= m[1].replace(/^0+/,'').replace(/^$/,'0'); // integer part (without sign and leading zeros)
let f= (m[2]||'0').replace(/0+$/,'').replace(/^$/,'0'); // fractional part (without last zeros)
let s= decStr[0]=='-'; // sign
let r=''; // result
if(i=='0') r='0';
while(i!='0') { // integer part
r=h[arbMod(i,16)]+r;
i=arbDivision(i,16);
}
if(fracDigits) r+=".";
let n = f.length;
for(let j=0; j<fracDigits; j++) { // frac part
let k= arbMultiply(f,16);
f = k.slice(-n);
let d= k.slice(0,k.length-n);
r+= d.length ? h[+d] : '0';
}
return (s?'-':'')+r;
}
// -----------
// TESTS
// -----------
let tests = [
["0",2],
["000",2],
["123",0],
["-123",0],
["00.000",2],
["255.75",5],
["-255.75",5],
["127.999",32],
];
console.log('Input Standard Abitrary');
tests.forEach(t=> {
let nonArb = (+t[0]).toString(16).padEnd(17,' ');
let arb = dec2HexArbitrary(t[0],t[1]);
console.log(t[0].padEnd(10,' '), nonArb, arb);
});
// Long Example (40 digits after dot)
let example = "123456789012345678901234567890.09876543210987654321"
console.log(`\nLong Example:`);
console.log('dec:',example);
console.log('hex: ',dec2HexArbitrary(example,40));
The problem basically how many padding zeros to expect.
If you expect string 01 and 11 from Number 1 and 17. it's better to use Buffer as a bridge, with which number is turn into bytes, and then the hex is just an output format of it. And the bytes organization is well controlled by Buffer functions, like writeUInt32BE, writeInt16LE, etc.
import { Buffer } from 'buffer';
function toHex(n) { // 4byte
const buff = Buffer.alloc(4);
buff.writeInt32BE(n);
return buff.toString('hex');
}
> toHex(1)
'00000001'
> toHex(17)
'00000011'
> toHex(-1)
'ffffffff'
> toHex(-1212)
'fffffb44'
> toHex(1212)
'000004bc'
Here's my solution:
hex = function(number) {
return '0x' + Math.abs(number).toString(16);
}
The question says: "How to convert decimal to hexadecimal in JavaScript". While, the question does not specify that the hexadecimal string should begin with a 0x prefix, anybody who writes code should know that 0x is added to hexadecimal codes to distinguish hexadecimal codes from programmatic identifiers and other numbers (1234 could be hexadecimal, decimal, or even octal).
Therefore, to correctly answer this question, for the purpose of script-writing, you must add the 0x prefix.
The Math.abs(N) function converts negatives to positives, and as a bonus, it doesn't look like somebody ran it through a wood-chipper.
The answer I wanted, would have had a field-width specifier, so we could for example show 8/16/32/64-bit values the way you would see them listed in a hexadecimal editing application. That, is the actual, correct answer.