I would like to convert numbers between different bases, such as hexadecimal and decimal.
Example: How do you convert hexadecimal 8F to decimal?
The API
To convert to a number from a hex string:
parseInt(string, radix)
string: Required. The string to be parsed
radix: Optional. A number (from 2 to 36) that represents the numeral system to be used
To convert from a number to a hex string:
NumberObject.toString(radix)
radix: Optional. Specifies the base radix you would like the number displayed as.
Example radix values:
2 - The number will show as a binary value
8 - The number will show as an octal value
16 - The number will show as an hexadecimal value
Example Usage
Integer value to hex:
var i = 10;
console.log( i.toString(16) );
Hex string to integer value:
var h = "a";
console.log( parseInt(h, 16) );
Integer value to decimal:
var d = 16;
console.log( d.toString(10) );
Update 2023-01-05: Now supports large numbers and floats via https://github.com/ryansmith94/baseroo
I came to this post needing to convert from base 10 to 62 and vice-versa. Whilst the solutions here are great, parseInt and toString only support base 2 to 36. So if anyone finds themselves in a similar position to me needing base 2 to 62, I've pasted my solution below.
function convertBase(value, from_base, to_base) {
var range = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'.split('');
var from_range = range.slice(0, from_base);
var to_range = range.slice(0, to_base);
var dec_value = value.split('').reverse().reduce(function (carry, digit, index) {
if (from_range.indexOf(digit) === -1) throw new Error('Invalid digit `'+digit+'` for base '+from_base+'.');
return carry += from_range.indexOf(digit) * (Math.pow(from_base, index));
}, 0);
var new_value = '';
while (dec_value > 0) {
new_value = to_range[dec_value % to_base] + new_value;
dec_value = (dec_value - (dec_value % to_base)) / to_base;
}
return new_value || '0';
}
You may try the following code, which also supports arbitrary precision numbers (larger than 2^53).
function convertBase(str, fromBase, toBase) {
const DIGITS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/";
const add = (x, y, base) => {
let z = [];
const n = Math.max(x.length, y.length);
let carry = 0;
let i = 0;
while (i < n || carry) {
const xi = i < x.length ? x[i] : 0;
const yi = i < y.length ? y[i] : 0;
const zi = carry + xi + yi;
z.push(zi % base);
carry = Math.floor(zi / base);
i++;
}
return z;
}
const multiplyByNumber = (num, x, base) => {
if (num < 0) return null;
if (num == 0) return [];
let result = [];
let power = x;
while (true) {
num & 1 && (result = add(result, power, base));
num = num >> 1;
if (num === 0) break;
power = add(power, power, base);
}
return result;
}
const parseToDigitsArray = (str, base) => {
const digits = str.split('');
let arr = [];
for (let i = digits.length - 1; i >= 0; i--) {
const n = DIGITS.indexOf(digits[i])
if (n == -1) return null;
arr.push(n);
}
return arr;
}
const digits = parseToDigitsArray(str, fromBase);
if (digits === null) return null;
let outArray = [];
let power = [1];
for (let i = 0; i < digits.length; i++) {
digits[i] && (outArray = add(outArray, multiplyByNumber(digits[i], power, toBase), toBase));
power = multiplyByNumber(fromBase, power, toBase);
}
let out = '';
for (let i = outArray.length - 1; i >= 0; i--)
out += DIGITS[outArray[i]];
return out;
}
Usage:
console.log(convertBase("5a2a9c826c75045be9ba8fbffc80c6f25a2a9c826c75045be9ba8fbffc80c6f2",16,64));
// Returns: 5EGD89ItghrWrGfL/O0NL9qaFO2r7k4m+CWzX/YwcrO
console.log(convertBase("5EGD89ItghrWrGfL/O0NL9qaFO2r7k4m+CWzX/YwcrO",64,16));
// Returns: 5a2a9c826c75045be9ba8fbffc80c6f25a2a9c826c75045be9ba8fbffc80c6f2
The basic code has been found here, I have a bit improved it to also support up to base 64.
The following diagram might help. Note that to convert from base 16 to base 2 you need to convert first to base 10 and then base 2.
This function generate decimal number to any base from 2 to 36.(as like javascript)But you can Increase the base more than 36 just by adding new character in keys[] like lowercase["a","b"]
function toBase(num, radix = 10) { // only i64 numbers
var keys = ['🤢', '😃', 2, 3, 4, 5, 6, 7, 8, 9, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
if (!(radix >= 2 && radix <= keys.length)) throw new RangeError("toBase() radix argument must be between 2 and " + keys.length)
if (num < 0) var isNegative = true
if (isNaN(num = Math.abs(+num))) return NaN
let output = [];
do {
let index = num % radix;
output.unshift(keys[index]);
num = Math.trunc(num / radix);
} while (num != 0);
if (isNegative) output.unshift('-')
return output.join("");
}
console.log(toBase("100",2))
Specify the radix you want to use as a parameter.
NOTE: This only works to convert from bases 2-36 to decimal and little values.
parseInt(string, radix)
parseInt("80", 10) // results in 80
parseInt("80", 16) // results in 128
// etc
About "little", parseInt("6f", 32) is fine (= 207), but any other little bigger will be also 207, 6f1, 6f11, ...
Well, I made a function that could translate from base 10 to any base. (This depends on how many strings you have in the array A, if it's more than that + 10 it'll run out of symbols), and I almost cried when I found out you could to it in less than 10 characters with that...
Add a bookmark and as URL insert this... I've done it the long but personal way. At least, mine can use a base which is higher than 36. You can add more symbols yourself, but if you want, I can make it for you...
var X = prompt("Choose your number");
var Y = prompt("Choose your base");
var Z = [];
var M = -1;
var A = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
var B = function() {
for (i = X; 0 < i; i = Math.floor(i / Y)) {
if(i % Y >= 10) {
Z.push(A[i % Y - 10]);
} else {
Z.push(i % Y);
}
M = M + 1;
}
for (j = M; j >= 0; j--) {
document.write(Z[j]);
}
};
B(); // Call function
Usually I use this function to convert from different bases.
For example, it returns "11111111" for both cases:
convertBase("ff", 16, 2) or convertBase(0xFF, 16, 2)
var convertBase = function(val, base1, base2) {
if (typeof(val) == "number") {
return parseInt(String(val)).toString(base2);
} else {
return parseInt(val.toString(), base1).toString(base2)
};
}
I've written a function to convert a JavaScript string from one base to another base, with the original base and the new base specified as parameters.
function convertFromBaseToBase(str, fromBase, toBase){
var num = parseInt(str, fromBase);
return num.toString(toBase);
}
alert(convertFromBaseToBase(10, 2, 10));
This function converts a number from base 10, to an arbitrary base:
function to_base(base, num) {
const largest_power = ~~(Math.log(num) / Math.log(base));
const result = [];
for (let pow = largest_power; pow >= 0; pow--) {
const digit = ~~(num / base ** pow);
num -= digit * base ** pow;
result.push(digit);
}
return result;
}
to_base(2, 13) // [1, 1, 0, 1]
to_base(10, 458) // [4, 5, 8]
to_base(32, 1024) //Â [1, 0, 0]
to_base(32, 1023) //Â [31, 31]
which can be useful if you want to use weird bases along with weird char-set
Using the parseInt function:
var noInBase10 = parseInt('8F',16);
Check the complete JS code to convert into different base
/**
* Convert From/To Binary/Decimal/Hexadecimal in JavaScript
* https://gist.github.com/shamshul2007/
* Copyright 2012-2015, Shamshul <shamshul2007#gmail.com>
* Licensed under The MIT License
* http://www.opensource.org/licenses/mit-license
*/
(function(){
var ConvertBase = function (num) {
return {
from : function (baseFrom) {
return {
to : function (baseTo) {
return parseInt(num, baseFrom).toString(baseTo);
}
};
}
};
};
// binary to decimal
ConvertBase.bin2dec = function (num) {
return ConvertBase(num).from(2).to(10);
};
// binary to hexadecimal
ConvertBase.bin2hex = function (num) {
return ConvertBase(num).from(2).to(16);
};
// decimal to binary
ConvertBase.dec2bin = function (num) {
return ConvertBase(num).from(10).to(2);
};
// decimal to hexadecimal
ConvertBase.dec2hex = function (num) {
return ConvertBase(num).from(10).to(16);
};
// hexadecimal to binary
ConvertBase.hex2bin = function (num) {
return ConvertBase(num).from(16).to(2);
};
// hexadecimal to decimal
ConvertBase.hex2dec = function (num) {
return ConvertBase(num).from(16).to(10);
};
//Octal to Decimal
ConvertBase.oct2dec = function (num) {
return ConvertBase(num).from(8).to(10);
};
//Decimal to Octal
ConvertBase.dec2oct = function (num) {
return ConvertBase(num).from(10).to(8);
};
this.ConvertBase = ConvertBase;
})(this);
/*
* Usage example:
* ConvertBase.bin2dec('1111'); // '15'
* ConvertBase.dec2hex('82'); // '52'
* ConvertBase.hex2bin('e2'); // '11100010'
* ConvertBase.dec2bin('153'); // '10011001'
* ConvertBase.hex2dec('1FE4ED63D55FA51E'); //'2298222722903156000'
* ConvertBase.oct2dec('777'); //'511'
* ConvertBase.dec2oct('551'); //'1047'
*/
Try the following code, optimised from Slavik Meltser's post, implements BASE n conversions with all the radix combinations between Base2 and Base256. This code accepts three sorts of arguments to define source and destination number systems:
by number system radix (e.g. 8)
by number system convention name (e.g. 'Bitcoin')
by giving custom numerals as an argument (e.g. ['0123456789ABCDEF'])
You'll see that some number system numerals have been hard-coded inside the class and will be used as default when you pass the radix as an argument. (.e.g. 64) When no hard-coded numeral exists (e.g. 16), default numerals are assigned for all radixes ranging between Base2 and Base256, which becomes very clear in the self-test further below.
function BASE() {
/**
* BASE n converter doing all the radix combinations between Base2 and Base256
* #param {String} str input number
* #param {Number|String|Array} fromBase input number system radix (Number, e.g. 64), convention name (String, e.g. 'Bitcoin') or range (Array)
* #param {Number|String|Array} toBASE output number system radix (Number), convention name (String) or range (Array e.g. ['0123456789'])
* #return {String} output number
*/
this.convert = function (str, fromBase, toBASE)
{
if(typeof(fromBase)=='object') { this.fromSymbols = fromBase[0] } else this.fromSymbols = this.getsymbols(fromBase);
if(typeof(toBASE) =='object') { this.toSymbols = toBASE[0] } else this.toSymbols = this.getsymbols(toBASE);
fromBase = this.fromSymbols.length; toBASE = this.toSymbols.length;
// PARSE INPUT DIGITS ARRAY
for(var _a = [0], str = str.split(''); str.length > 0 && _a[_a.push(this.fromSymbols.indexOf(str.pop())) - 1] >= 0;);
var _d = _a.shift() + _a[_a.length-1]>=0 ? _a : null; if (_d === null) return null;
// BASE CONVERSION
for (var _n = 0,_a = [],_p = [1]; _n < _d.length; _n++) { _a = add(_a, mul(_d[_n], _p, toBASE), toBASE); _p = mul(fromBase, _p, toBASE) }
// PARSE OUTPUT DIGITS ARRAY
for (var _n = _a.length - 1, _o = ''; _n >= 0; _o += this.toSymbols[_a[_n--]]);
return _o.length==0?this.toSymbols[0]:_o;
}
this.symbols = {
32:function(){return this["base32hex"]},
36:["[0-9][A-Z]"],
45:function(){return this["qr-alnum"]},
58:function(){return this["Bitcoin"]},
64:["[A-Z][a-z][0-9]+/"],
85:function(){return this["RFC 1924"]},
91:["[A-Z][a-z][0-9]!#$%&()*+,./:;<=>?#[]^_`{|}~\""],
94:["[!-~]"],
"geohash": ["[0-9][b-h]jkmn[p-z]"], // base 32
"RFC 4648": ["[A-Z][2-7]"], // base 32
"base32hex": ["[0-9][A-V]"], // base 32
"qr-alnum":["[0-9][A-Z] $%*+-./:"], // base 45
"Bitcoin": ["[1-9][A-H]JKLMN[P-Z][a-k][m-z]"], // base 58
"RFC 1924": ["[0-9][A-Z][a-z]!#$%&()*+-;<=>?#^_`{|}~"] // base 85
}
this.getsymbols = function(index) {
if(typeof(this.symbols[index])=="undefined") this.symbols[index] = index<95?this.rng(index<64?"[0-9][A-Z][a-z]+":"[A-Z][a-z][0-9][!-/][:-#][[-`][{-~]").substring(0,index):this.rng("[\x00-\xff]").substring(256-index,256);
if(typeof(this.symbols[index])=="function") this.symbols[index] = this.symbols[index](); // process references
if(typeof(this.symbols[index])=="object") this.symbols[index] = this.rng(this.symbols[index][0]); // process range_replace
return this.symbols[index];
}
this.rng = function(_s) {
var _a = _s.match(/\[.-.\]/); if(_a==null) return _s; else { _a=[_a[0].charCodeAt(1),_a[0].charCodeAt(3)];
return this.rng(_s.replace(RegExp("\\[(\\x"+("0"+_a[0].toString(16)).slice(-2)+"-\\x"+_a[1].toString(16)+")\\]","g")
,String.fromCharCode(..." ".repeat(_a[1]-_a[0]+1).split("").map((_e,_i)=>_i+_a[0])) )) }
}
this.selftest = function() {
var _a={}; for(var _o in this.symbols) _a[_o] = this.getsymbols(_o).length; // built-in symbols
for(_o=2;_o<=95;_o++) _a[_o] = this.getsymbols(_o).length; _a[256]=256; // symbol range 2-95 + 256 (96-255 is similar)
var _s = "",_a = Object.keys(_a).sort(function(a,b){return _a[a]-_a[b]}); // sort merged list
for(var _i in _a) { // iterate number systems
_o = {fromBase:10, toBASE:_a[_i]}; var _r = this.convert("",10,_o.toBASE)
_s += "\r\n\oBASE.convert(n, '"+_o.fromBase+"', '"+_o.toBASE+"') ["+this.fromSymbols+"] ["+this.toSymbols+"]\r\n"
for(var _n=0;_n<(this.fromSymbols.length+2);_n++) { // iterate numbers
_r = this.convert(String(_n),_o.fromBase,_o.toBASE)
_s += _n+(String(_n)==this.convert(_r,_o.toBASE,_o.fromBase)?">":"?")+"["+_r+"] ";
}
}
return _s
}
var add = function(x, y, base) {
var _m = Math.max(x.length, y.length);
for(var _c = _n = 0,_r = []; _n < _m || _c; _c = Math.floor(_z / base)) {
var _z = _c + (_n < x.length ? x[_n] : 0) + (_n < y.length ? y[_n] : 0);
var _n = _r.push(_z % base);
}
return _r;
}
var mul = function(x, pow, base) {
for(var _r = x < 0 ? null : []; x > 0; x = x >> 1) {
if(x & 1) _r = add(_r, pow, base);
pow = add(pow, pow, base);
}
return _r;
}
}
Usage:
// quick test, convert from base45 to base32, using custom symbols for base85 and back to base45
var oBASE = new BASE();
var n = "THIS IS A NUMBER"; // Base 45 code = 'qr-alnum'
console.log(n); // Result: 'THIS IS A NUMBER'
var n = oBASE.convert(n,"qr-alnum",32); // Base 45 to Base 32 = 'base32hex'
console.log(n); // Result: '4ONI84LCTLJ1U08G1N'
var s85 = oBASE.rng("[0-9][a-z][A-Z].-:+=^!/*?&<>()[]{}#%$#"); // 32/Z85 custom symbols
var n = oBASE.convert(n,"base32hex",[s85]); // 'base2hex' to custom Base 85
console.log(n); // Result: 'fnaxrZP)?5d[DG'
var n = oBASE.convert(n,[s85],45); // Custom Base 85 to Base 45 = 'qr-alnum'
console.log(n); // Result: 'THIS IS A NUMBER'
function BASE(){this.convert=function(o,r,n){this.fromSymbols="object"==typeof r?r[0]:this.getsymbols(r),this.toSymbols="object"==typeof n?n[0]:this.getsymbols(n),r=this.fromSymbols.length,n=this.toSymbols.length;var i=[0];for(o=o.split("");o.length>0&&i[i.push(this.fromSymbols.indexOf(o.pop()))-1]>=0;);var h=i.shift()+i[i.length-1]>=0?i:null;if(null===h)return null;for(var e=0,l=(i=[],[1]);e<h.length;e++)i=t(i,s(h[e],l,n),n),l=s(r,l,n);e=i.length-1;for(var m="";e>=0;m+=this.toSymbols[i[e--]]);return 0==m.length?this.toSymbols[0]:m},this.symbols={32:function(){return this.base32hex},36:["[0-9][A-Z]"],45:function(){return this["qr-alnum"]},58:function(){return this.Bitcoin},64:["[A-Z][a-z][0-9]+/"],85:function(){return this["RFC 1924"]},91:['[A-Z][a-z][0-9]!#$%&()*+,./:;<=>?#[]^_`{|}~"'],94:["[!-~]"],geohash:["[0-9][b-h]jkmn[p-z]"],"RFC 4648":["[A-Z][2-7]"],base32hex:["[0-9][A-V]"],"qr-alnum":["[0-9][A-Z] $%*+-./:"],Bitcoin:["[1-9][A-H]JKLMN[P-Z][a-k][m-z]"],"RFC 1924":["[0-9][A-Z][a-z]!#$%&()*+-;<=>?#^_`{|}~"]},this.getsymbols=function(t){return void 0===this.symbols[t]&&(this.symbols[t]=t<95?this.rng(t<64?"[0-9][A-Z][a-z]+":"[A-Z][a-z][0-9][!-/][:-#][[-`][{-~]").substring(0,t):this.rng("[\0-ÿ]").substring(256-t,256)),"function"==typeof this.symbols[t]&&(this.symbols[t]=this.symbols[t]()),"object"==typeof this.symbols[t]&&(this.symbols[t]=this.rng(this.symbols[t][0])),this.symbols[t]},this.rng=function(t){var s=t.match(/\[.-.\]/);return null==s?t:(s=[s[0].charCodeAt(1),s[0].charCodeAt(3)],this.rng(t.replace(RegExp("\\[(\\x"+("0"+s[0].toString(16)).slice(-2)+"-\\x"+s[1].toString(16)+")\\]","g"),String.fromCharCode(..." ".repeat(s[1]-s[0]+1).split("").map((t,o)=>o+s[0])))))},this.selftest=function(){var t={};for(var s in this.symbols)t[s]=this.getsymbols(s).length;for(s=2;s<=95;s++)t[s]=this.getsymbols(s).length;t[256]=256;var o="";t=Object.keys(t).sort(function(s,o){return t[s]-t[o]});for(var r in t){s={fromBase:10,toBASE:t[r]};var n=this.convert("",10,s.toBASE);o+="\r\noBASE.convert(n, '"+s.fromBase+"', '"+s.toBASE+"') ["+this.fromSymbols+"] ["+this.toSymbols+"]\r\n";for(var i=0;i<this.fromSymbols.length+2;i++)n=this.convert(String(i),s.fromBase,s.toBASE),o+=i+(String(i)==this.convert(n,s.toBASE,s.fromBase)?">":"?")+"["+n+"] "}return o};var t=function(t,s,o){for(var r=Math.max(t.length,s.length),n=e=0,i=[];e<r||n;n=Math.floor(h/o))var h=n+(e<t.length?t[e]:0)+(e<s.length?s[e]:0),e=i.push(h%o);return i},s=function(s,o,r){for(var n=s<0?null:[];s>0;s>>=1)1&s&&(n=t(n,o,r)),o=t(o,o,r);return n}}
Self-Test:
// quick test, convert from base45 to base32, using custom symbols for base85 and back to base45
var oBASE = new BASE();
console.log(oBASE.selftest())
function BASE(){this.convert=function(o,r,n){this.fromSymbols="object"==typeof r?r[0]:this.getsymbols(r),this.toSymbols="object"==typeof n?n[0]:this.getsymbols(n),r=this.fromSymbols.length,n=this.toSymbols.length;var i=[0];for(o=o.split("");o.length>0&&i[i.push(this.fromSymbols.indexOf(o.pop()))-1]>=0;);var h=i.shift()+i[i.length-1]>=0?i:null;if(null===h)return null;for(var e=0,l=(i=[],[1]);e<h.length;e++)i=t(i,s(h[e],l,n),n),l=s(r,l,n);e=i.length-1;for(var m="";e>=0;m+=this.toSymbols[i[e--]]);return 0==m.length?this.toSymbols[0]:m},this.symbols={32:function(){return this.base32hex},36:["[0-9][A-Z]"],45:function(){return this["qr-alnum"]},58:function(){return this.Bitcoin},64:["[A-Z][a-z][0-9]+/"],85:function(){return this["RFC 1924"]},91:['[A-Z][a-z][0-9]!#$%&()*+,./:;<=>?#[]^_`{|}~"'],94:["[!-~]"],geohash:["[0-9][b-h]jkmn[p-z]"],"RFC 4648":["[A-Z][2-7]"],base32hex:["[0-9][A-V]"],"qr-alnum":["[0-9][A-Z] $%*+-./:"],Bitcoin:["[1-9][A-H]JKLMN[P-Z][a-k][m-z]"],"RFC 1924":["[0-9][A-Z][a-z]!#$%&()*+-;<=>?#^_`{|}~"]},this.getsymbols=function(t){return void 0===this.symbols[t]&&(this.symbols[t]=t<95?this.rng(t<64?"[0-9][A-Z][a-z]+":"[A-Z][a-z][0-9][!-/][:-#][[-`][{-~]").substring(0,t):this.rng("[\0-ÿ]").substring(256-t,256)),"function"==typeof this.symbols[t]&&(this.symbols[t]=this.symbols[t]()),"object"==typeof this.symbols[t]&&(this.symbols[t]=this.rng(this.symbols[t][0])),this.symbols[t]},this.rng=function(t){var s=t.match(/\[.-.\]/);return null==s?t:(s=[s[0].charCodeAt(1),s[0].charCodeAt(3)],this.rng(t.replace(RegExp("\\[(\\x"+("0"+s[0].toString(16)).slice(-2)+"-\\x"+s[1].toString(16)+")\\]","g"),String.fromCharCode(..." ".repeat(s[1]-s[0]+1).split("").map((t,o)=>o+s[0])))))},this.selftest=function(){var t={};for(var s in this.symbols)t[s]=this.getsymbols(s).length;for(s=2;s<=95;s++)t[s]=this.getsymbols(s).length;t[256]=256;var o="";t=Object.keys(t).sort(function(s,o){return t[s]-t[o]});for(var r in t){s={fromBase:10,toBASE:t[r]};var n=this.convert("",10,s.toBASE);o+="\r\noBASE.convert(n, '"+s.fromBase+"', '"+s.toBASE+"') ["+this.fromSymbols+"] ["+this.toSymbols+"]\r\n";for(var i=0;i<this.fromSymbols.length+2;i++)n=this.convert(String(i),s.fromBase,s.toBASE),o+=i+(String(i)==this.convert(n,s.toBASE,s.fromBase)?">":"?")+"["+n+"] "}return o};var t=function(t,s,o){for(var r=Math.max(t.length,s.length),n=e=0,i=[];e<r||n;n=Math.floor(h/o))var h=n+(e<t.length?t[e]:0)+(e<s.length?s[e]:0),e=i.push(h%o);return i},s=function(s,o,r){for(var n=s<0?null:[];s>0;s>>=1)1&s&&(n=t(n,o,r)),o=t(o,o,r);return n}}
to convert numbers into different bases in JavaScript or typescript using the following ways.
function binary(number) {
console.log((number >>> 0).toString(2)); //base 2 for binary
}
binary(-7);
function octal(number) {
console.log(number.toString(8)); //base 8 for octal
}
octal(15);
function hex(number) {
console.log(number.toString(16)); //base 16 for hex
}
hex(15);
here in the binary function, you can use number.toString(2) function, but the problem occurs when representing negative numbers. so that you can use the unsigned right shift bitwise operator (>>>) to fix this issue.
I am writing this answer simply because I was kinda stupid to understand the difference between parseInt and .toString().
Here is the difference
parseInt
parseInt(str, base) will convert the str to an Integer and base here is used to tell parseInt which base the str is in. I thought the base here was what the str would get converted to. But thats not true. parseInt is just used to convert a number in any base to an integer in base10.
.toString()
number.toString(base) is used to convert the number into a number with base base and it assumes that number is in Integer form. So if the number is in hex format and you want to convert it to binary you need to convert the number first to Integer using parseInt and then you can use this function to change the base.
Hope this helps if you are as stupid as me. :)
You can also convert number in hexadecimal to decimal as follows:
var a="8F";
var b=a.split("");
var result=0;var hex_multiplier=1;
for(var i=0;i<b.length;i++){
result +=parseInt(b[i],16)*hex_multiplier;
hex_multiplier *=16;
}
console.log(result);
where you can change a with any hexadecimal number and get the result in decimal form.
You can use JavaScript's built-in integer literals for some scenarios:
function binaryToDecimal(binaryString) {
return Number('0b' + binaryString.replace('-', '')) * signOf(binaryString);;
}
function octalToDecimal(octalString) {
return Number('0o' + octalString.replace('-', '')) * signOf(octalString);
}
function hexToDecimal(hexString) {
return Number('0x' + hexString.replace('-', '')) * signOf(hexString);
}
function signOf(n) {
return n.trim()[0] == '-' ? -1 : 1;
}
console.log(binaryToDecimal('-0101'),
octalToDecimal('-052171'),
hexToDecimal('deadbeef'));
This code converts a number to an arbitrary-large base, outputting an array of digits.
function convertBase(num, base) {
var result = [];
while(num >= 1) {
result.unshift(num % base);
num = Math.floor(num / base);
}
return result;
}
console.log(convertBase(100, 12)); // [8, 4]
console.log(convertBase(5114, 64)); // [1, 15, 58]
TypeScript Implementation that supports decimal and int:
class Digit {
private readonly digitMap: Map<string, number>;
constructor(readonly digits: string, readonly maxDigits = 10) {
this.digitMap = new Map<string, number>();
for (let i = 0; i < digits.length; i += 1) {
if (digits[i] === ".") {
throw new TypeError(`Digits should not contain the "." mark.`);
}
if (this.digitMap.has(digits[i])) {
throw new TypeError(`Duplicated digit character.`);
}
this.digitMap.set(digits[i], i);
}
}
to = (x: number) => {
const int = Math.floor(x);
const dec = x - int;
let intRemains = int;
let intResult = "";
while (true) {
intResult = this.digits[intRemains % this.digits.length] + intResult;
intRemains = Math.floor(intRemains / this.digits.length);
if (intRemains === 0) break;
}
if (dec > 0) {
let decRemains = dec;
let decResult = "";
for (let i = 0; i < this.maxDigits; i += 1) {
const stepCache = decRemains * this.digits.length;
const decInt = Math.floor(stepCache);
decResult = decResult + this.digits[decInt];
decRemains = stepCache - decInt;
if (decRemains === 0) break;
}
if (decResult === "0") return intResult;
return intResult + "." + decResult;
}
return intResult;
};
from = (x: string) => {
const splitted = x.split(".");
if (splitted.length > 2) return Number.NaN;
const [int, dec] = splitted;
let result = 0;
for (let i = 0; i < int.length; i += 1) {
const digit = int[int.length - i - 1];
const oct = this.digitMap.get(digit);
if (oct === undefined) return Number.NaN;
result += oct * Math.pow(this.digits.length, i);
}
if (dec) {
for (let i = 0; i < dec.length; i += 1) {
const digit = dec[i];
const oct = this.digitMap.get(digit);
if (oct === undefined) return Number.NaN;
result += oct * Math.pow(this.digits.length, 0 - i - 1);
}
}
return result;
};
}
Here're the example about how to use it:
Creating the converter:
const d = new Digit("0123456789");
Convert a number to string:
d.to(1.2345);
Convert a string to number:
d.from("1.2345");
You can also set the second parameter to control the maximum number of decimal places, for example:
const d0 = new Digit("abcdABCD", 10);
d0.to(0.96);
// a.DBdAbcbDcD
const d1 = new Digit("abcdABCD", 20);
d1.to(0.96);
// a.DBdAbcbDcDacAdCBC
Monkey patched Number prototype for all radixes up to and including 64
( inspired by and derived from #nirvana's answer )
NumberToStringPatched.__patched = NumberToStringPatched;
if (Number.prototype.toString.__patched!==NumberToStringPatched) {
NumberToStringPatched.__unpatched = Number.prototype.toString;
Number.prototype.toString = NumberToStringPatched;
}
NumberParseIntPatched.__patched = NumberParseIntPatched;
if (Number.parseInt.__patched!==NumberParseIntPatched) {
NumberParseIntPatched.__unpatched = Number.parseInt;
Number.parseInt = NumberParseIntPatched;
}
function NumberToStringPatched(base=10) {
if (base<33||base>64) return NumberToStringPatched.__unpatched.call(this,base);
return convertToBase(this,base);
}
function NumberParseIntPatched(str,base=10) {
if (base<33||base>64) return NumberParseIntPatched.__unpatched.call(this,str,base);
return convertFromBase(str,base);
}
const numberCharSet=(()=>{
let chars = "0123456789";
for (let c='a';c<='z';c=String.fromCharCode(c.charCodeAt(0)+1)) {
chars+=c;
}
for (let c='A';c<='Z';c=String.fromCharCode(c.charCodeAt(0)+1)) {
chars+=c;
}
return (chars+'_$').split('');
})();
function convertToBase(num, base) {
var result = '';
while(num >= 1) {
result = numberCharSet[num % base]+result;
num = Math.floor(num / base);
}
return result;
}
function convertFromBase(str, base) {
let charset = numberCharSet.slice(0,base);
if (typeof str==='number') str=str.toString(base);
if (base <= 26) str=str.toLowerCase();
let digits = str.split('').map(function(c){
let x = charset.indexOf(c);
if (x<0) throw new Error("invalid digit for given radix "+base+': '+c);
return x;
});
let result = digits.shift();
while (digits.length) {
result=(result*base)+digits.shift();
}
return result;
}
for (let i = 0;i<64;i++) {
console.log(i.toString(64));
}
console.log(9000);
console.log(9 * 10 * 10 * 10);
console.log(0xf000);
console.log(15 * 16 * 16 * 16);
console.log(Number.parseInt('$000',64));
console.log(63 * 64 * 64 * 64);
Your Own recursion method for creating base2 conversions.
As mentioned by the users above
let n = 13; console.log(n.toString(2)); will result in 13 conversion from base 10 to base 2.
But in case if you want to program the same. I have written a recursive method to do the same. which just simply divide by 2 and then count remainders.
// #author Tarandeep Singh :: Created recursive converter from base 10 to base 2
// #date : 2017-04-11
// Convert Base 10 to Base 2, We should reverse the output
// For Example base10to2(10) = "0101" just do res = base10to2(10).split('').reverse().join();
function base10to2(val, res = '') {
if (val >= 2) {
res += '' + val % 2;
return base10to2(val = Math.floor(val / 2), res);
} else {
res += '' + 1
return res;
}
}
let n = 13;
var result = base10to2(n).split('').reverse().join();
document.write(`Converting ${n} into Base2 is ${result}`);
Related
Given a non-negative number say 1213, it should return 12 because there are 12 possible integers similar to 1213 i.e., 1123,1132,1213,1231,1312,1321,2113,2131,2311,312,3121 and 3211. Same with 10, it should return 1 and 12 should return 2 and if the number is 120 it should return 4 as combinations are 120,102,210,201.
You can use this formula to get the total number of unique permutations excluding permutations with leading zero.
Lets define some symbols:
n = Total Number of digits
z = Number of zeros
r1, r2, ..., rn = repetition count of digits with count > 1
fact(p) = factorial of number of p
Total permutations = (n - z) * fact(n - 1) / fact(r1) * fact(r2) * .... * fact(rn)
For example, for 1213,
n = 4, z = 0, r1 (digit 1) = 2
permutations = (4 - 0) * fact(4 - 1) / fact(2) = 4 * 6 / 2 = 12
You can easily convert this to program.
function factorial(n) {
if (n <=1)
return 1;
return n * factorial(n-1);
}
function getPermutations(number) {
var n = number.toString().split('').length;
var r = {};
number.toString().split('').forEach(function(digit){
r[digit] = r[digit] || 0;
r[digit] += 1;
});
var z = number.toString().split('').reduce(function(count, digit) {
return (digit === '0') ? count + 1 : count;
}, 0);
var denominator = Object.keys(r).map(function (key) { return r[key]; }).reduce(function(result, curr) {
return result * factorial(curr);
}, 1);
//console.log(n, r, z);
return (n - z) * factorial(n - 1) / denominator;
}
var result = getPermutations(1216);
console.log(result);
Note : This is basic implementation and would not be the most optimum. Also, factorial calculation involves large numbers and would probably fail for large inputs.
You are looking for an anagram algorithm :
This script find every anagram of a string then delete every number starting with zero :
var allAnagrams = function(arr) {
var anagrams = {};
arr.forEach(function(str) {
var recurse = function(ana, str) {
if (str === '')
anagrams[ana] = 1;
for (var i = 0; i < str.length; i++)
recurse(ana + str[i], str.slice(0, i) + str.slice(i + 1));
};
recurse('', str);
});
return Object.keys(anagrams);
}
var arr = ['120']; //declare your number
var anag = allAnagrams(arr); //send it to the function
for (var i in anag) { //delete leading 0
if((anag[i].charAt(0)) === '0' ) {
anag.splice(i);
}
}
console.log(anag); //print array
console.log(anag.length); // print length
Here the output will be :
["102", "120", "201", "210"]
4
I would like to convert numbers between different bases, such as hexadecimal and decimal.
Example: How do you convert hexadecimal 8F to decimal?
The API
To convert to a number from a hex string:
parseInt(string, radix)
string: Required. The string to be parsed
radix: Optional. A number (from 2 to 36) that represents the numeral system to be used
To convert from a number to a hex string:
NumberObject.toString(radix)
radix: Optional. Specifies the base radix you would like the number displayed as.
Example radix values:
2 - The number will show as a binary value
8 - The number will show as an octal value
16 - The number will show as an hexadecimal value
Example Usage
Integer value to hex:
var i = 10;
console.log( i.toString(16) );
Hex string to integer value:
var h = "a";
console.log( parseInt(h, 16) );
Integer value to decimal:
var d = 16;
console.log( d.toString(10) );
Update 2023-01-05: Now supports large numbers and floats via https://github.com/ryansmith94/baseroo
I came to this post needing to convert from base 10 to 62 and vice-versa. Whilst the solutions here are great, parseInt and toString only support base 2 to 36. So if anyone finds themselves in a similar position to me needing base 2 to 62, I've pasted my solution below.
function convertBase(value, from_base, to_base) {
var range = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/'.split('');
var from_range = range.slice(0, from_base);
var to_range = range.slice(0, to_base);
var dec_value = value.split('').reverse().reduce(function (carry, digit, index) {
if (from_range.indexOf(digit) === -1) throw new Error('Invalid digit `'+digit+'` for base '+from_base+'.');
return carry += from_range.indexOf(digit) * (Math.pow(from_base, index));
}, 0);
var new_value = '';
while (dec_value > 0) {
new_value = to_range[dec_value % to_base] + new_value;
dec_value = (dec_value - (dec_value % to_base)) / to_base;
}
return new_value || '0';
}
You may try the following code, which also supports arbitrary precision numbers (larger than 2^53).
function convertBase(str, fromBase, toBase) {
const DIGITS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/";
const add = (x, y, base) => {
let z = [];
const n = Math.max(x.length, y.length);
let carry = 0;
let i = 0;
while (i < n || carry) {
const xi = i < x.length ? x[i] : 0;
const yi = i < y.length ? y[i] : 0;
const zi = carry + xi + yi;
z.push(zi % base);
carry = Math.floor(zi / base);
i++;
}
return z;
}
const multiplyByNumber = (num, x, base) => {
if (num < 0) return null;
if (num == 0) return [];
let result = [];
let power = x;
while (true) {
num & 1 && (result = add(result, power, base));
num = num >> 1;
if (num === 0) break;
power = add(power, power, base);
}
return result;
}
const parseToDigitsArray = (str, base) => {
const digits = str.split('');
let arr = [];
for (let i = digits.length - 1; i >= 0; i--) {
const n = DIGITS.indexOf(digits[i])
if (n == -1) return null;
arr.push(n);
}
return arr;
}
const digits = parseToDigitsArray(str, fromBase);
if (digits === null) return null;
let outArray = [];
let power = [1];
for (let i = 0; i < digits.length; i++) {
digits[i] && (outArray = add(outArray, multiplyByNumber(digits[i], power, toBase), toBase));
power = multiplyByNumber(fromBase, power, toBase);
}
let out = '';
for (let i = outArray.length - 1; i >= 0; i--)
out += DIGITS[outArray[i]];
return out;
}
Usage:
console.log(convertBase("5a2a9c826c75045be9ba8fbffc80c6f25a2a9c826c75045be9ba8fbffc80c6f2",16,64));
// Returns: 5EGD89ItghrWrGfL/O0NL9qaFO2r7k4m+CWzX/YwcrO
console.log(convertBase("5EGD89ItghrWrGfL/O0NL9qaFO2r7k4m+CWzX/YwcrO",64,16));
// Returns: 5a2a9c826c75045be9ba8fbffc80c6f25a2a9c826c75045be9ba8fbffc80c6f2
The basic code has been found here, I have a bit improved it to also support up to base 64.
The following diagram might help. Note that to convert from base 16 to base 2 you need to convert first to base 10 and then base 2.
This function generate decimal number to any base from 2 to 36.(as like javascript)But you can Increase the base more than 36 just by adding new character in keys[] like lowercase["a","b"]
function toBase(num, radix = 10) { // only i64 numbers
var keys = ['🤢', '😃', 2, 3, 4, 5, 6, 7, 8, 9, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
if (!(radix >= 2 && radix <= keys.length)) throw new RangeError("toBase() radix argument must be between 2 and " + keys.length)
if (num < 0) var isNegative = true
if (isNaN(num = Math.abs(+num))) return NaN
let output = [];
do {
let index = num % radix;
output.unshift(keys[index]);
num = Math.trunc(num / radix);
} while (num != 0);
if (isNegative) output.unshift('-')
return output.join("");
}
console.log(toBase("100",2))
Specify the radix you want to use as a parameter.
NOTE: This only works to convert from bases 2-36 to decimal and little values.
parseInt(string, radix)
parseInt("80", 10) // results in 80
parseInt("80", 16) // results in 128
// etc
About "little", parseInt("6f", 32) is fine (= 207), but any other little bigger will be also 207, 6f1, 6f11, ...
Well, I made a function that could translate from base 10 to any base. (This depends on how many strings you have in the array A, if it's more than that + 10 it'll run out of symbols), and I almost cried when I found out you could to it in less than 10 characters with that...
Add a bookmark and as URL insert this... I've done it the long but personal way. At least, mine can use a base which is higher than 36. You can add more symbols yourself, but if you want, I can make it for you...
var X = prompt("Choose your number");
var Y = prompt("Choose your base");
var Z = [];
var M = -1;
var A = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
var B = function() {
for (i = X; 0 < i; i = Math.floor(i / Y)) {
if(i % Y >= 10) {
Z.push(A[i % Y - 10]);
} else {
Z.push(i % Y);
}
M = M + 1;
}
for (j = M; j >= 0; j--) {
document.write(Z[j]);
}
};
B(); // Call function
Usually I use this function to convert from different bases.
For example, it returns "11111111" for both cases:
convertBase("ff", 16, 2) or convertBase(0xFF, 16, 2)
var convertBase = function(val, base1, base2) {
if (typeof(val) == "number") {
return parseInt(String(val)).toString(base2);
} else {
return parseInt(val.toString(), base1).toString(base2)
};
}
I've written a function to convert a JavaScript string from one base to another base, with the original base and the new base specified as parameters.
function convertFromBaseToBase(str, fromBase, toBase){
var num = parseInt(str, fromBase);
return num.toString(toBase);
}
alert(convertFromBaseToBase(10, 2, 10));
This function converts a number from base 10, to an arbitrary base:
function to_base(base, num) {
const largest_power = ~~(Math.log(num) / Math.log(base));
const result = [];
for (let pow = largest_power; pow >= 0; pow--) {
const digit = ~~(num / base ** pow);
num -= digit * base ** pow;
result.push(digit);
}
return result;
}
to_base(2, 13) // [1, 1, 0, 1]
to_base(10, 458) // [4, 5, 8]
to_base(32, 1024) //Â [1, 0, 0]
to_base(32, 1023) //Â [31, 31]
which can be useful if you want to use weird bases along with weird char-set
Using the parseInt function:
var noInBase10 = parseInt('8F',16);
Check the complete JS code to convert into different base
/**
* Convert From/To Binary/Decimal/Hexadecimal in JavaScript
* https://gist.github.com/shamshul2007/
* Copyright 2012-2015, Shamshul <shamshul2007#gmail.com>
* Licensed under The MIT License
* http://www.opensource.org/licenses/mit-license
*/
(function(){
var ConvertBase = function (num) {
return {
from : function (baseFrom) {
return {
to : function (baseTo) {
return parseInt(num, baseFrom).toString(baseTo);
}
};
}
};
};
// binary to decimal
ConvertBase.bin2dec = function (num) {
return ConvertBase(num).from(2).to(10);
};
// binary to hexadecimal
ConvertBase.bin2hex = function (num) {
return ConvertBase(num).from(2).to(16);
};
// decimal to binary
ConvertBase.dec2bin = function (num) {
return ConvertBase(num).from(10).to(2);
};
// decimal to hexadecimal
ConvertBase.dec2hex = function (num) {
return ConvertBase(num).from(10).to(16);
};
// hexadecimal to binary
ConvertBase.hex2bin = function (num) {
return ConvertBase(num).from(16).to(2);
};
// hexadecimal to decimal
ConvertBase.hex2dec = function (num) {
return ConvertBase(num).from(16).to(10);
};
//Octal to Decimal
ConvertBase.oct2dec = function (num) {
return ConvertBase(num).from(8).to(10);
};
//Decimal to Octal
ConvertBase.dec2oct = function (num) {
return ConvertBase(num).from(10).to(8);
};
this.ConvertBase = ConvertBase;
})(this);
/*
* Usage example:
* ConvertBase.bin2dec('1111'); // '15'
* ConvertBase.dec2hex('82'); // '52'
* ConvertBase.hex2bin('e2'); // '11100010'
* ConvertBase.dec2bin('153'); // '10011001'
* ConvertBase.hex2dec('1FE4ED63D55FA51E'); //'2298222722903156000'
* ConvertBase.oct2dec('777'); //'511'
* ConvertBase.dec2oct('551'); //'1047'
*/
Try the following code, optimised from Slavik Meltser's post, implements BASE n conversions with all the radix combinations between Base2 and Base256. This code accepts three sorts of arguments to define source and destination number systems:
by number system radix (e.g. 8)
by number system convention name (e.g. 'Bitcoin')
by giving custom numerals as an argument (e.g. ['0123456789ABCDEF'])
You'll see that some number system numerals have been hard-coded inside the class and will be used as default when you pass the radix as an argument. (.e.g. 64) When no hard-coded numeral exists (e.g. 16), default numerals are assigned for all radixes ranging between Base2 and Base256, which becomes very clear in the self-test further below.
function BASE() {
/**
* BASE n converter doing all the radix combinations between Base2 and Base256
* #param {String} str input number
* #param {Number|String|Array} fromBase input number system radix (Number, e.g. 64), convention name (String, e.g. 'Bitcoin') or range (Array)
* #param {Number|String|Array} toBASE output number system radix (Number), convention name (String) or range (Array e.g. ['0123456789'])
* #return {String} output number
*/
this.convert = function (str, fromBase, toBASE)
{
if(typeof(fromBase)=='object') { this.fromSymbols = fromBase[0] } else this.fromSymbols = this.getsymbols(fromBase);
if(typeof(toBASE) =='object') { this.toSymbols = toBASE[0] } else this.toSymbols = this.getsymbols(toBASE);
fromBase = this.fromSymbols.length; toBASE = this.toSymbols.length;
// PARSE INPUT DIGITS ARRAY
for(var _a = [0], str = str.split(''); str.length > 0 && _a[_a.push(this.fromSymbols.indexOf(str.pop())) - 1] >= 0;);
var _d = _a.shift() + _a[_a.length-1]>=0 ? _a : null; if (_d === null) return null;
// BASE CONVERSION
for (var _n = 0,_a = [],_p = [1]; _n < _d.length; _n++) { _a = add(_a, mul(_d[_n], _p, toBASE), toBASE); _p = mul(fromBase, _p, toBASE) }
// PARSE OUTPUT DIGITS ARRAY
for (var _n = _a.length - 1, _o = ''; _n >= 0; _o += this.toSymbols[_a[_n--]]);
return _o.length==0?this.toSymbols[0]:_o;
}
this.symbols = {
32:function(){return this["base32hex"]},
36:["[0-9][A-Z]"],
45:function(){return this["qr-alnum"]},
58:function(){return this["Bitcoin"]},
64:["[A-Z][a-z][0-9]+/"],
85:function(){return this["RFC 1924"]},
91:["[A-Z][a-z][0-9]!#$%&()*+,./:;<=>?#[]^_`{|}~\""],
94:["[!-~]"],
"geohash": ["[0-9][b-h]jkmn[p-z]"], // base 32
"RFC 4648": ["[A-Z][2-7]"], // base 32
"base32hex": ["[0-9][A-V]"], // base 32
"qr-alnum":["[0-9][A-Z] $%*+-./:"], // base 45
"Bitcoin": ["[1-9][A-H]JKLMN[P-Z][a-k][m-z]"], // base 58
"RFC 1924": ["[0-9][A-Z][a-z]!#$%&()*+-;<=>?#^_`{|}~"] // base 85
}
this.getsymbols = function(index) {
if(typeof(this.symbols[index])=="undefined") this.symbols[index] = index<95?this.rng(index<64?"[0-9][A-Z][a-z]+":"[A-Z][a-z][0-9][!-/][:-#][[-`][{-~]").substring(0,index):this.rng("[\x00-\xff]").substring(256-index,256);
if(typeof(this.symbols[index])=="function") this.symbols[index] = this.symbols[index](); // process references
if(typeof(this.symbols[index])=="object") this.symbols[index] = this.rng(this.symbols[index][0]); // process range_replace
return this.symbols[index];
}
this.rng = function(_s) {
var _a = _s.match(/\[.-.\]/); if(_a==null) return _s; else { _a=[_a[0].charCodeAt(1),_a[0].charCodeAt(3)];
return this.rng(_s.replace(RegExp("\\[(\\x"+("0"+_a[0].toString(16)).slice(-2)+"-\\x"+_a[1].toString(16)+")\\]","g")
,String.fromCharCode(..." ".repeat(_a[1]-_a[0]+1).split("").map((_e,_i)=>_i+_a[0])) )) }
}
this.selftest = function() {
var _a={}; for(var _o in this.symbols) _a[_o] = this.getsymbols(_o).length; // built-in symbols
for(_o=2;_o<=95;_o++) _a[_o] = this.getsymbols(_o).length; _a[256]=256; // symbol range 2-95 + 256 (96-255 is similar)
var _s = "",_a = Object.keys(_a).sort(function(a,b){return _a[a]-_a[b]}); // sort merged list
for(var _i in _a) { // iterate number systems
_o = {fromBase:10, toBASE:_a[_i]}; var _r = this.convert("",10,_o.toBASE)
_s += "\r\n\oBASE.convert(n, '"+_o.fromBase+"', '"+_o.toBASE+"') ["+this.fromSymbols+"] ["+this.toSymbols+"]\r\n"
for(var _n=0;_n<(this.fromSymbols.length+2);_n++) { // iterate numbers
_r = this.convert(String(_n),_o.fromBase,_o.toBASE)
_s += _n+(String(_n)==this.convert(_r,_o.toBASE,_o.fromBase)?">":"?")+"["+_r+"] ";
}
}
return _s
}
var add = function(x, y, base) {
var _m = Math.max(x.length, y.length);
for(var _c = _n = 0,_r = []; _n < _m || _c; _c = Math.floor(_z / base)) {
var _z = _c + (_n < x.length ? x[_n] : 0) + (_n < y.length ? y[_n] : 0);
var _n = _r.push(_z % base);
}
return _r;
}
var mul = function(x, pow, base) {
for(var _r = x < 0 ? null : []; x > 0; x = x >> 1) {
if(x & 1) _r = add(_r, pow, base);
pow = add(pow, pow, base);
}
return _r;
}
}
Usage:
// quick test, convert from base45 to base32, using custom symbols for base85 and back to base45
var oBASE = new BASE();
var n = "THIS IS A NUMBER"; // Base 45 code = 'qr-alnum'
console.log(n); // Result: 'THIS IS A NUMBER'
var n = oBASE.convert(n,"qr-alnum",32); // Base 45 to Base 32 = 'base32hex'
console.log(n); // Result: '4ONI84LCTLJ1U08G1N'
var s85 = oBASE.rng("[0-9][a-z][A-Z].-:+=^!/*?&<>()[]{}#%$#"); // 32/Z85 custom symbols
var n = oBASE.convert(n,"base32hex",[s85]); // 'base2hex' to custom Base 85
console.log(n); // Result: 'fnaxrZP)?5d[DG'
var n = oBASE.convert(n,[s85],45); // Custom Base 85 to Base 45 = 'qr-alnum'
console.log(n); // Result: 'THIS IS A NUMBER'
function BASE(){this.convert=function(o,r,n){this.fromSymbols="object"==typeof r?r[0]:this.getsymbols(r),this.toSymbols="object"==typeof n?n[0]:this.getsymbols(n),r=this.fromSymbols.length,n=this.toSymbols.length;var i=[0];for(o=o.split("");o.length>0&&i[i.push(this.fromSymbols.indexOf(o.pop()))-1]>=0;);var h=i.shift()+i[i.length-1]>=0?i:null;if(null===h)return null;for(var e=0,l=(i=[],[1]);e<h.length;e++)i=t(i,s(h[e],l,n),n),l=s(r,l,n);e=i.length-1;for(var m="";e>=0;m+=this.toSymbols[i[e--]]);return 0==m.length?this.toSymbols[0]:m},this.symbols={32:function(){return this.base32hex},36:["[0-9][A-Z]"],45:function(){return this["qr-alnum"]},58:function(){return this.Bitcoin},64:["[A-Z][a-z][0-9]+/"],85:function(){return this["RFC 1924"]},91:['[A-Z][a-z][0-9]!#$%&()*+,./:;<=>?#[]^_`{|}~"'],94:["[!-~]"],geohash:["[0-9][b-h]jkmn[p-z]"],"RFC 4648":["[A-Z][2-7]"],base32hex:["[0-9][A-V]"],"qr-alnum":["[0-9][A-Z] $%*+-./:"],Bitcoin:["[1-9][A-H]JKLMN[P-Z][a-k][m-z]"],"RFC 1924":["[0-9][A-Z][a-z]!#$%&()*+-;<=>?#^_`{|}~"]},this.getsymbols=function(t){return void 0===this.symbols[t]&&(this.symbols[t]=t<95?this.rng(t<64?"[0-9][A-Z][a-z]+":"[A-Z][a-z][0-9][!-/][:-#][[-`][{-~]").substring(0,t):this.rng("[\0-ÿ]").substring(256-t,256)),"function"==typeof this.symbols[t]&&(this.symbols[t]=this.symbols[t]()),"object"==typeof this.symbols[t]&&(this.symbols[t]=this.rng(this.symbols[t][0])),this.symbols[t]},this.rng=function(t){var s=t.match(/\[.-.\]/);return null==s?t:(s=[s[0].charCodeAt(1),s[0].charCodeAt(3)],this.rng(t.replace(RegExp("\\[(\\x"+("0"+s[0].toString(16)).slice(-2)+"-\\x"+s[1].toString(16)+")\\]","g"),String.fromCharCode(..." ".repeat(s[1]-s[0]+1).split("").map((t,o)=>o+s[0])))))},this.selftest=function(){var t={};for(var s in this.symbols)t[s]=this.getsymbols(s).length;for(s=2;s<=95;s++)t[s]=this.getsymbols(s).length;t[256]=256;var o="";t=Object.keys(t).sort(function(s,o){return t[s]-t[o]});for(var r in t){s={fromBase:10,toBASE:t[r]};var n=this.convert("",10,s.toBASE);o+="\r\noBASE.convert(n, '"+s.fromBase+"', '"+s.toBASE+"') ["+this.fromSymbols+"] ["+this.toSymbols+"]\r\n";for(var i=0;i<this.fromSymbols.length+2;i++)n=this.convert(String(i),s.fromBase,s.toBASE),o+=i+(String(i)==this.convert(n,s.toBASE,s.fromBase)?">":"?")+"["+n+"] "}return o};var t=function(t,s,o){for(var r=Math.max(t.length,s.length),n=e=0,i=[];e<r||n;n=Math.floor(h/o))var h=n+(e<t.length?t[e]:0)+(e<s.length?s[e]:0),e=i.push(h%o);return i},s=function(s,o,r){for(var n=s<0?null:[];s>0;s>>=1)1&s&&(n=t(n,o,r)),o=t(o,o,r);return n}}
Self-Test:
// quick test, convert from base45 to base32, using custom symbols for base85 and back to base45
var oBASE = new BASE();
console.log(oBASE.selftest())
function BASE(){this.convert=function(o,r,n){this.fromSymbols="object"==typeof r?r[0]:this.getsymbols(r),this.toSymbols="object"==typeof n?n[0]:this.getsymbols(n),r=this.fromSymbols.length,n=this.toSymbols.length;var i=[0];for(o=o.split("");o.length>0&&i[i.push(this.fromSymbols.indexOf(o.pop()))-1]>=0;);var h=i.shift()+i[i.length-1]>=0?i:null;if(null===h)return null;for(var e=0,l=(i=[],[1]);e<h.length;e++)i=t(i,s(h[e],l,n),n),l=s(r,l,n);e=i.length-1;for(var m="";e>=0;m+=this.toSymbols[i[e--]]);return 0==m.length?this.toSymbols[0]:m},this.symbols={32:function(){return this.base32hex},36:["[0-9][A-Z]"],45:function(){return this["qr-alnum"]},58:function(){return this.Bitcoin},64:["[A-Z][a-z][0-9]+/"],85:function(){return this["RFC 1924"]},91:['[A-Z][a-z][0-9]!#$%&()*+,./:;<=>?#[]^_`{|}~"'],94:["[!-~]"],geohash:["[0-9][b-h]jkmn[p-z]"],"RFC 4648":["[A-Z][2-7]"],base32hex:["[0-9][A-V]"],"qr-alnum":["[0-9][A-Z] $%*+-./:"],Bitcoin:["[1-9][A-H]JKLMN[P-Z][a-k][m-z]"],"RFC 1924":["[0-9][A-Z][a-z]!#$%&()*+-;<=>?#^_`{|}~"]},this.getsymbols=function(t){return void 0===this.symbols[t]&&(this.symbols[t]=t<95?this.rng(t<64?"[0-9][A-Z][a-z]+":"[A-Z][a-z][0-9][!-/][:-#][[-`][{-~]").substring(0,t):this.rng("[\0-ÿ]").substring(256-t,256)),"function"==typeof this.symbols[t]&&(this.symbols[t]=this.symbols[t]()),"object"==typeof this.symbols[t]&&(this.symbols[t]=this.rng(this.symbols[t][0])),this.symbols[t]},this.rng=function(t){var s=t.match(/\[.-.\]/);return null==s?t:(s=[s[0].charCodeAt(1),s[0].charCodeAt(3)],this.rng(t.replace(RegExp("\\[(\\x"+("0"+s[0].toString(16)).slice(-2)+"-\\x"+s[1].toString(16)+")\\]","g"),String.fromCharCode(..." ".repeat(s[1]-s[0]+1).split("").map((t,o)=>o+s[0])))))},this.selftest=function(){var t={};for(var s in this.symbols)t[s]=this.getsymbols(s).length;for(s=2;s<=95;s++)t[s]=this.getsymbols(s).length;t[256]=256;var o="";t=Object.keys(t).sort(function(s,o){return t[s]-t[o]});for(var r in t){s={fromBase:10,toBASE:t[r]};var n=this.convert("",10,s.toBASE);o+="\r\noBASE.convert(n, '"+s.fromBase+"', '"+s.toBASE+"') ["+this.fromSymbols+"] ["+this.toSymbols+"]\r\n";for(var i=0;i<this.fromSymbols.length+2;i++)n=this.convert(String(i),s.fromBase,s.toBASE),o+=i+(String(i)==this.convert(n,s.toBASE,s.fromBase)?">":"?")+"["+n+"] "}return o};var t=function(t,s,o){for(var r=Math.max(t.length,s.length),n=e=0,i=[];e<r||n;n=Math.floor(h/o))var h=n+(e<t.length?t[e]:0)+(e<s.length?s[e]:0),e=i.push(h%o);return i},s=function(s,o,r){for(var n=s<0?null:[];s>0;s>>=1)1&s&&(n=t(n,o,r)),o=t(o,o,r);return n}}
to convert numbers into different bases in JavaScript or typescript using the following ways.
function binary(number) {
console.log((number >>> 0).toString(2)); //base 2 for binary
}
binary(-7);
function octal(number) {
console.log(number.toString(8)); //base 8 for octal
}
octal(15);
function hex(number) {
console.log(number.toString(16)); //base 16 for hex
}
hex(15);
here in the binary function, you can use number.toString(2) function, but the problem occurs when representing negative numbers. so that you can use the unsigned right shift bitwise operator (>>>) to fix this issue.
You can also convert number in hexadecimal to decimal as follows:
var a="8F";
var b=a.split("");
var result=0;var hex_multiplier=1;
for(var i=0;i<b.length;i++){
result +=parseInt(b[i],16)*hex_multiplier;
hex_multiplier *=16;
}
console.log(result);
where you can change a with any hexadecimal number and get the result in decimal form.
You can use JavaScript's built-in integer literals for some scenarios:
function binaryToDecimal(binaryString) {
return Number('0b' + binaryString.replace('-', '')) * signOf(binaryString);;
}
function octalToDecimal(octalString) {
return Number('0o' + octalString.replace('-', '')) * signOf(octalString);
}
function hexToDecimal(hexString) {
return Number('0x' + hexString.replace('-', '')) * signOf(hexString);
}
function signOf(n) {
return n.trim()[0] == '-' ? -1 : 1;
}
console.log(binaryToDecimal('-0101'),
octalToDecimal('-052171'),
hexToDecimal('deadbeef'));
This code converts a number to an arbitrary-large base, outputting an array of digits.
function convertBase(num, base) {
var result = [];
while(num >= 1) {
result.unshift(num % base);
num = Math.floor(num / base);
}
return result;
}
console.log(convertBase(100, 12)); // [8, 4]
console.log(convertBase(5114, 64)); // [1, 15, 58]
TypeScript Implementation that supports decimal and int:
class Digit {
private readonly digitMap: Map<string, number>;
constructor(readonly digits: string, readonly maxDigits = 10) {
this.digitMap = new Map<string, number>();
for (let i = 0; i < digits.length; i += 1) {
if (digits[i] === ".") {
throw new TypeError(`Digits should not contain the "." mark.`);
}
if (this.digitMap.has(digits[i])) {
throw new TypeError(`Duplicated digit character.`);
}
this.digitMap.set(digits[i], i);
}
}
to = (x: number) => {
const int = Math.floor(x);
const dec = x - int;
let intRemains = int;
let intResult = "";
while (true) {
intResult = this.digits[intRemains % this.digits.length] + intResult;
intRemains = Math.floor(intRemains / this.digits.length);
if (intRemains === 0) break;
}
if (dec > 0) {
let decRemains = dec;
let decResult = "";
for (let i = 0; i < this.maxDigits; i += 1) {
const stepCache = decRemains * this.digits.length;
const decInt = Math.floor(stepCache);
decResult = decResult + this.digits[decInt];
decRemains = stepCache - decInt;
if (decRemains === 0) break;
}
if (decResult === "0") return intResult;
return intResult + "." + decResult;
}
return intResult;
};
from = (x: string) => {
const splitted = x.split(".");
if (splitted.length > 2) return Number.NaN;
const [int, dec] = splitted;
let result = 0;
for (let i = 0; i < int.length; i += 1) {
const digit = int[int.length - i - 1];
const oct = this.digitMap.get(digit);
if (oct === undefined) return Number.NaN;
result += oct * Math.pow(this.digits.length, i);
}
if (dec) {
for (let i = 0; i < dec.length; i += 1) {
const digit = dec[i];
const oct = this.digitMap.get(digit);
if (oct === undefined) return Number.NaN;
result += oct * Math.pow(this.digits.length, 0 - i - 1);
}
}
return result;
};
}
Here're the example about how to use it:
Creating the converter:
const d = new Digit("0123456789");
Convert a number to string:
d.to(1.2345);
Convert a string to number:
d.from("1.2345");
You can also set the second parameter to control the maximum number of decimal places, for example:
const d0 = new Digit("abcdABCD", 10);
d0.to(0.96);
// a.DBdAbcbDcD
const d1 = new Digit("abcdABCD", 20);
d1.to(0.96);
// a.DBdAbcbDcDacAdCBC
Monkey patched Number prototype for all radixes up to and including 64
( inspired by and derived from #nirvana's answer )
NumberToStringPatched.__patched = NumberToStringPatched;
if (Number.prototype.toString.__patched!==NumberToStringPatched) {
NumberToStringPatched.__unpatched = Number.prototype.toString;
Number.prototype.toString = NumberToStringPatched;
}
NumberParseIntPatched.__patched = NumberParseIntPatched;
if (Number.parseInt.__patched!==NumberParseIntPatched) {
NumberParseIntPatched.__unpatched = Number.parseInt;
Number.parseInt = NumberParseIntPatched;
}
function NumberToStringPatched(base=10) {
if (base<33||base>64) return NumberToStringPatched.__unpatched.call(this,base);
return convertToBase(this,base);
}
function NumberParseIntPatched(str,base=10) {
if (base<33||base>64) return NumberParseIntPatched.__unpatched.call(this,str,base);
return convertFromBase(str,base);
}
const numberCharSet=(()=>{
let chars = "0123456789";
for (let c='a';c<='z';c=String.fromCharCode(c.charCodeAt(0)+1)) {
chars+=c;
}
for (let c='A';c<='Z';c=String.fromCharCode(c.charCodeAt(0)+1)) {
chars+=c;
}
return (chars+'_$').split('');
})();
function convertToBase(num, base) {
var result = '';
while(num >= 1) {
result = numberCharSet[num % base]+result;
num = Math.floor(num / base);
}
return result;
}
function convertFromBase(str, base) {
let charset = numberCharSet.slice(0,base);
if (typeof str==='number') str=str.toString(base);
if (base <= 26) str=str.toLowerCase();
let digits = str.split('').map(function(c){
let x = charset.indexOf(c);
if (x<0) throw new Error("invalid digit for given radix "+base+': '+c);
return x;
});
let result = digits.shift();
while (digits.length) {
result=(result*base)+digits.shift();
}
return result;
}
for (let i = 0;i<64;i++) {
console.log(i.toString(64));
}
console.log(9000);
console.log(9 * 10 * 10 * 10);
console.log(0xf000);
console.log(15 * 16 * 16 * 16);
console.log(Number.parseInt('$000',64));
console.log(63 * 64 * 64 * 64);
I am writing this answer simply because I was kinda stupid to understand the difference between parseInt and .toString().
Here is the difference
parseInt
parseInt(str, base) will convert the str to an Integer and base here is used to tell parseInt which base the str is in. I thought the base here was what the str would get converted to. But thats not true. parseInt is just used to convert a number in any base to an integer in base10.
.toString()
number.toString(base) is used to convert the number into a number with base base and it assumes that number is in Integer form. So if the number is in hex format and you want to convert it to binary you need to convert the number first to Integer using parseInt and then you can use this function to change the base.
Hope this helps if you are as stupid as me. :)
Your Own recursion method for creating base2 conversions.
As mentioned by the users above
let n = 13; console.log(n.toString(2)); will result in 13 conversion from base 10 to base 2.
But in case if you want to program the same. I have written a recursive method to do the same. which just simply divide by 2 and then count remainders.
// #author Tarandeep Singh :: Created recursive converter from base 10 to base 2
// #date : 2017-04-11
// Convert Base 10 to Base 2, We should reverse the output
// For Example base10to2(10) = "0101" just do res = base10to2(10).split('').reverse().join();
function base10to2(val, res = '') {
if (val >= 2) {
res += '' + val % 2;
return base10to2(val = Math.floor(val / 2), res);
} else {
res += '' + 1
return res;
}
}
let n = 13;
var result = base10to2(n).split('').reverse().join();
document.write(`Converting ${n} into Base2 is ${result}`);
Suppose I have a value of 15.7784514, I want to display it 15.77 with no rounding.
var num = parseFloat(15.7784514);
document.write(num.toFixed(1)+"<br />");
document.write(num.toFixed(2)+"<br />");
document.write(num.toFixed(3)+"<br />");
document.write(num.toFixed(10));
Results in -
15.8
15.78
15.778
15.7784514000
How do I display 15.77?
Convert the number into a string, match the number up to the second decimal place:
function calc(theform) {
var num = theform.original.value, rounded = theform.rounded
var with2Decimals = num.toString().match(/^-?\d+(?:\.\d{0,2})?/)[0]
rounded.value = with2Decimals
}
<form onsubmit="return calc(this)">
Original number: <input name="original" type="text" onkeyup="calc(form)" onchange="calc(form)" />
<br />"Rounded" number: <input name="rounded" type="text" placeholder="readonly" readonly>
</form>
The toFixed method fails in some cases unlike toString, so be very careful with it.
Update 5 Nov 2016
New answer, always accurate
function toFixed(num, fixed) {
var re = new RegExp('^-?\\d+(?:\.\\d{0,' + (fixed || -1) + '})?');
return num.toString().match(re)[0];
}
As floating point math in javascript will always have edge cases, the previous solution will be accurate most of the time which is not good enough.
There are some solutions to this like num.toPrecision, BigDecimal.js, and accounting.js.
Yet, I believe that merely parsing the string will be the simplest and always accurate.
Basing the update on the well written regex from the accepted answer by #Gumbo, this new toFixed function will always work as expected.
Old answer, not always accurate.
Roll your own toFixed function:
function toFixed(num, fixed) {
fixed = fixed || 0;
fixed = Math.pow(10, fixed);
return Math.floor(num * fixed) / fixed;
}
Another single-line solution :
number = Math.trunc(number*100)/100
I used 100 because you want to truncate to the second digit, but a more flexible solution would be :
number = Math.trunc(number*Math.pow(10, digits))/Math.pow(10, digits)
where digits is the amount of decimal digits to keep.
See Math.trunc specs for details and browser compatibility.
I opted to write this instead to manually remove the remainder with strings so I don't have to deal with the math issues that come with numbers:
num = num.toString(); //If it's not already a String
num = num.slice(0, (num.indexOf("."))+3); //With 3 exposing the hundredths place
Number(num); //If you need it back as a Number
This will give you "15.77" with num = 15.7784514;
Update (Jan 2021)
Depending on its range, a number in javascript may be shown in scientific notation. For example, if you type 0.0000001 in the console, you may see it as 1e-7, whereas 0.000001 appears unchanged (0.000001).
If your application works on a range of numbers for which scientific notation is not involved, you can just ignore this update and use the original answer below.
This update is about adding a function that checks if the number is in scientific format and, if so, converts it into decimal format. Here I'm proposing this one, but you can use any other function that achieves the same goal, according to your application's needs:
function toFixed(x) {
if (Math.abs(x) < 1.0) {
let e = parseInt(x.toString().split('e-')[1]);
if (e) {
x *= Math.pow(10,e-1);
x = '0.' + (new Array(e)).join('0') + x.toString().substring(2);
}
} else {
let e = parseInt(x.toString().split('+')[1]);
if (e > 20) {
e -= 20;
x /= Math.pow(10,e);
x += (new Array(e+1)).join('0');
}
}
return x;
}
Now just apply that function to the parameter (that's the only change with respect to the original answer):
function toFixedTrunc(x, n) {
x = toFixed(x)
// From here on the code is the same than the original answer
const v = (typeof x === 'string' ? x : x.toString()).split('.');
if (n <= 0) return v[0];
let f = v[1] || '';
if (f.length > n) return `${v[0]}.${f.substr(0,n)}`;
while (f.length < n) f += '0';
return `${v[0]}.${f}`
}
This updated version addresses also a case mentioned in a comment:
toFixedTrunc(0.000000199, 2) => "0.00"
Again, choose what fits your application needs at best.
Original answer (October 2017)
General solution to truncate (no rounding) a number to the n-th decimal digit and convert it to a string with exactly n decimal digits, for any n≥0.
function toFixedTrunc(x, n) {
const v = (typeof x === 'string' ? x : x.toString()).split('.');
if (n <= 0) return v[0];
let f = v[1] || '';
if (f.length > n) return `${v[0]}.${f.substr(0,n)}`;
while (f.length < n) f += '0';
return `${v[0]}.${f}`
}
where x can be either a number (which gets converted into a string) or a string.
Here are some tests for n=2 (including the one requested by OP):
0 => 0.00
0.01 => 0.01
0.5839 => 0.58
0.999 => 0.99
1.01 => 1.01
2 => 2.00
2.551 => 2.55
2.99999 => 2.99
4.27 => 4.27
15.7784514 => 15.77
123.5999 => 123.59
And for some other values of n:
15.001097 => 15.0010 (n=4)
0.000003298 => 0.0000032 (n=7)
0.000003298257899 => 0.000003298257 (n=12)
parseInt is faster then Math.floor
function floorFigure(figure, decimals){
if (!decimals) decimals = 2;
var d = Math.pow(10,decimals);
return (parseInt(figure*d)/d).toFixed(decimals);
};
floorFigure(123.5999) => "123.59"
floorFigure(123.5999, 3) => "123.599"
num = 19.66752
f = num.toFixed(3).slice(0,-1)
alert(f)
This will return 19.66
Simple do this
number = parseInt(number * 100)/100;
Just truncate the digits:
function truncDigits(inputNumber, digits) {
const fact = 10 ** digits;
return Math.floor(inputNumber * fact) / fact;
}
This is not a safe alternative, as many others commented examples with numbers that turn into exponential notation, that scenery is not covered by this function
// typescript
// function formatLimitDecimals(value: number, decimals: number): number {
function formatLimitDecimals(value, decimals) {
const stringValue = value.toString();
if(stringValue.includes('e')) {
// TODO: remove exponential notation
throw 'invald number';
} else {
const [integerPart, decimalPart] = stringValue.split('.');
if(decimalPart) {
return +[integerPart, decimalPart.slice(0, decimals)].join('.')
} else {
return integerPart;
}
}
}
console.log(formatLimitDecimals(4.156, 2)); // 4.15
console.log(formatLimitDecimals(4.156, 8)); // 4.156
console.log(formatLimitDecimals(4.156, 0)); // 4
console.log(formatLimitDecimals(0, 4)); // 0
// not covered
console.log(formatLimitDecimals(0.000000199, 2)); // 0.00
These solutions do work, but to me seem unnecessarily complicated. I personally like to use the modulus operator to obtain the remainder of a division operation, and remove that. Assuming that num = 15.7784514:
num-=num%.01;
This is equivalent to saying num = num - (num % .01).
I fixed using following simple way-
var num = 15.7784514;
Math.floor(num*100)/100;
Results will be 15.77
My version for positive numbers:
function toFixed_norounding(n,p)
{
var result = n.toFixed(p);
return result <= n ? result: (result - Math.pow(0.1,p)).toFixed(p);
}
Fast, pretty, obvious. (version for positive numbers)
The answers here didn't help me, it kept rounding up or giving me the wrong decimal.
my solution converts your decimal to a string, extracts the characters and then returns the whole thing as a number.
function Dec2(num) {
num = String(num);
if(num.indexOf('.') !== -1) {
var numarr = num.split(".");
if (numarr.length == 1) {
return Number(num);
}
else {
return Number(numarr[0]+"."+numarr[1].charAt(0)+numarr[1].charAt(1));
}
}
else {
return Number(num);
}
}
Dec2(99); // 99
Dec2(99.9999999); // 99.99
Dec2(99.35154); // 99.35
Dec2(99.8); // 99.8
Dec2(10265.985475); // 10265.98
The following code works very good for me:
num.toString().match(/.\*\\..{0,2}|.\*/)[0];
This worked well for me. I hope it will fix your issues too.
function toFixedNumber(number) {
const spitedValues = String(number.toLocaleString()).split('.');
let decimalValue = spitedValues.length > 1 ? spitedValues[1] : '';
decimalValue = decimalValue.concat('00').substr(0,2);
return '$'+spitedValues[0] + '.' + decimalValue;
}
// 5.56789 ----> $5.56
// 0.342 ----> $0.34
// -10.3484534 ----> $-10.34
// 600 ----> $600.00
function convertNumber(){
var result = toFixedNumber(document.getElementById("valueText").value);
document.getElementById("resultText").value = result;
}
function toFixedNumber(number) {
const spitedValues = String(number.toLocaleString()).split('.');
let decimalValue = spitedValues.length > 1 ? spitedValues[1] : '';
decimalValue = decimalValue.concat('00').substr(0,2);
return '$'+spitedValues[0] + '.' + decimalValue;
}
<div>
<input type="text" id="valueText" placeholder="Input value here..">
<br>
<button onclick="convertNumber()" >Convert</button>
<br><hr>
<input type="text" id="resultText" placeholder="result" readonly="true">
</div>
An Easy way to do it is the next but is necessary ensure that the amount parameter is given as a string.
function truncate(amountAsString, decimals = 2){
var dotIndex = amountAsString.indexOf('.');
var toTruncate = dotIndex !== -1 && ( amountAsString.length > dotIndex + decimals + 1);
var approach = Math.pow(10, decimals);
var amountToTruncate = toTruncate ? amountAsString.slice(0, dotIndex + decimals +1) : amountAsString;
return toTruncate
? Math.floor(parseFloat(amountToTruncate) * approach ) / approach
: parseFloat(amountAsString);
}
console.log(truncate("7.99999")); //OUTPUT ==> 7.99
console.log(truncate("7.99999", 3)); //OUTPUT ==> 7.999
console.log(truncate("12.799999999999999")); //OUTPUT ==> 7.99
Here you are. An answer that shows yet another way to solve the problem:
// For the sake of simplicity, here is a complete function:
function truncate(numToBeTruncated, numOfDecimals) {
var theNumber = numToBeTruncated.toString();
var pointIndex = theNumber.indexOf('.');
return +(theNumber.slice(0, pointIndex > -1 ? ++numOfDecimals + pointIndex : undefined));
}
Note the use of + before the final expression. That is to convert our truncated, sliced string back to number type.
Hope it helps!
truncate without zeroes
function toTrunc(value,n){
return Math.floor(value*Math.pow(10,n))/(Math.pow(10,n));
}
or
function toTrunc(value,n){
x=(value.toString()+".0").split(".");
return parseFloat(x[0]+"."+x[1].substr(0,n));
}
test:
toTrunc(17.4532,2) //17.45
toTrunc(177.4532,1) //177.4
toTrunc(1.4532,1) //1.4
toTrunc(.4,2) //0.4
truncate with zeroes
function toTruncFixed(value,n){
return toTrunc(value,n).toFixed(n);
}
test:
toTrunc(17.4532,2) //17.45
toTrunc(177.4532,1) //177.4
toTrunc(1.4532,1) //1.4
toTrunc(.4,2) //0.40
If you exactly wanted to truncate to 2 digits of precision, you can go with a simple logic:
function myFunction(number) {
var roundedNumber = number.toFixed(2);
if (roundedNumber > number)
{
roundedNumber = roundedNumber - 0.01;
}
return roundedNumber;
}
I used (num-0.05).toFixed(1) to get the second decimal floored.
It's more reliable to get two floating points without rounding.
Reference Answer
var number = 10.5859;
var fixed2FloatPoints = parseInt(number * 100) / 100;
console.log(fixed2FloatPoints);
Thank You !
My solution in typescript (can easily be ported to JS):
/**
* Returns the price with correct precision as a string
*
* #param price The price in decimal to be formatted.
* #param decimalPlaces The number of decimal places to use
* #return string The price in Decimal formatting.
*/
type toDecimal = (price: number, decimalPlaces?: number) => string;
const toDecimalOdds: toDecimal = (
price: number,
decimalPlaces: number = 2,
): string => {
const priceString: string = price.toString();
const pointIndex: number = priceString.indexOf('.');
// Return the integer part if decimalPlaces is 0
if (decimalPlaces === 0) {
return priceString.substr(0, pointIndex);
}
// Return value with 0s appended after decimal if the price is an integer
if (pointIndex === -1) {
const padZeroString: string = '0'.repeat(decimalPlaces);
return `${priceString}.${padZeroString}`;
}
// If numbers after decimal are less than decimalPlaces, append with 0s
const padZeroLen: number = priceString.length - pointIndex - 1;
if (padZeroLen > 0 && padZeroLen < decimalPlaces) {
const padZeroString: string = '0'.repeat(padZeroLen);
return `${priceString}${padZeroString}`;
}
return priceString.substr(0, pointIndex + decimalPlaces + 1);
};
Test cases:
expect(filters.toDecimalOdds(3.14159)).toBe('3.14');
expect(filters.toDecimalOdds(3.14159, 2)).toBe('3.14');
expect(filters.toDecimalOdds(3.14159, 0)).toBe('3');
expect(filters.toDecimalOdds(3.14159, 10)).toBe('3.1415900000');
expect(filters.toDecimalOdds(8.2)).toBe('8.20');
Any improvements?
Another solution, that truncates and round:
function round (number, decimals, truncate) {
if (truncate) {
number = number.toFixed(decimals + 1);
return parseFloat(number.slice(0, -1));
}
var n = Math.pow(10.0, decimals);
return Math.round(number * n) / n;
};
function limitDecimalsWithoutRounding(val, decimals){
let parts = val.toString().split(".");
return parseFloat(parts[0] + "." + parts[1].substring(0, decimals));
}
var num = parseFloat(15.7784514);
var new_num = limitDecimalsWithoutRounding(num, 2);
Roll your own toFixed function: for positive values Math.floor works fine.
function toFixed(num, fixed) {
fixed = fixed || 0;
fixed = Math.pow(10, fixed);
return Math.floor(num * fixed) / fixed;
}
For negative values Math.floor is round of the values. So you can use Math.ceil instead.
Example,
Math.ceil(-15.778665 * 10000) / 10000 = -15.7786
Math.floor(-15.778665 * 10000) / 10000 = -15.7787 // wrong.
Gumbo's second solution, with the regular expression, does work but is slow because of the regular expression. Gumbo's first solution fails in certain situations due to imprecision in floating points numbers. See the JSFiddle for a demonstration and a benchmark. The second solution takes about 1636 nanoseconds per call on my current system, Intel Core i5-2500 CPU at 3.30 GHz.
The solution I've written involves adding a small compensation to take care of floating point imprecision. It is basically instantaneous, i.e. on the order of nanoseconds. I clocked 2 nanoseconds per call but the JavaScript timers are not very precise or granular. Here is the JS Fiddle and the code.
function toFixedWithoutRounding (value, precision)
{
var factorError = Math.pow(10, 14);
var factorTruncate = Math.pow(10, 14 - precision);
var factorDecimal = Math.pow(10, precision);
return Math.floor(Math.floor(value * factorError + 1) / factorTruncate) / factorDecimal;
}
var values = [1.1299999999, 1.13, 1.139999999, 1.14, 1.14000000001, 1.13 * 100];
for (var i = 0; i < values.length; i++)
{
var value = values[i];
console.log(value + " --> " + toFixedWithoutRounding(value, 2));
}
for (var i = 0; i < values.length; i++)
{
var value = values[i];
console.log(value + " --> " + toFixedWithoutRounding(value, 4));
}
console.log("type of result is " + typeof toFixedWithoutRounding(1.13 * 100 / 100, 2));
// Benchmark
var value = 1.13 * 100;
var startTime = new Date();
var numRun = 1000000;
var nanosecondsPerMilliseconds = 1000000;
for (var run = 0; run < numRun; run++)
toFixedWithoutRounding(value, 2);
var endTime = new Date();
var timeDiffNs = nanosecondsPerMilliseconds * (endTime - startTime);
var timePerCallNs = timeDiffNs / numRun;
console.log("Time per call (nanoseconds): " + timePerCallNs);
Building on David D's answer:
function NumberFormat(num,n) {
var num = (arguments[0] != null) ? arguments[0] : 0;
var n = (arguments[1] != null) ? arguments[1] : 2;
if(num > 0){
num = String(num);
if(num.indexOf('.') !== -1) {
var numarr = num.split(".");
if (numarr.length > 1) {
if(n > 0){
var temp = numarr[0] + ".";
for(var i = 0; i < n; i++){
if(i < numarr[1].length){
temp += numarr[1].charAt(i);
}
}
num = Number(temp);
}
}
}
}
return Number(num);
}
console.log('NumberFormat(123.85,2)',NumberFormat(123.85,2));
console.log('NumberFormat(123.851,2)',NumberFormat(123.851,2));
console.log('NumberFormat(0.85,2)',NumberFormat(0.85,2));
console.log('NumberFormat(0.851,2)',NumberFormat(0.851,2));
console.log('NumberFormat(0.85156,2)',NumberFormat(0.85156,2));
console.log('NumberFormat(0.85156,4)',NumberFormat(0.85156,4));
console.log('NumberFormat(0.85156,8)',NumberFormat(0.85156,8));
console.log('NumberFormat(".85156",2)',NumberFormat(".85156",2));
console.log('NumberFormat("0.85156",2)',NumberFormat("0.85156",2));
console.log('NumberFormat("1005.85156",2)',NumberFormat("1005.85156",2));
console.log('NumberFormat("0",2)',NumberFormat("0",2));
console.log('NumberFormat("",2)',NumberFormat("",2));
console.log('NumberFormat(85156,8)',NumberFormat(85156,8));
console.log('NumberFormat("85156",2)',NumberFormat("85156",2));
console.log('NumberFormat("85156.",2)',NumberFormat("85156.",2));
// NumberFormat(123.85,2) 123.85
// NumberFormat(123.851,2) 123.85
// NumberFormat(0.85,2) 0.85
// NumberFormat(0.851,2) 0.85
// NumberFormat(0.85156,2) 0.85
// NumberFormat(0.85156,4) 0.8515
// NumberFormat(0.85156,8) 0.85156
// NumberFormat(".85156",2) 0.85
// NumberFormat("0.85156",2) 0.85
// NumberFormat("1005.85156",2) 1005.85
// NumberFormat("0",2) 0
// NumberFormat("",2) 0
// NumberFormat(85156,8) 85156
// NumberFormat("85156",2) 85156
// NumberFormat("85156.",2) 85156
Already there are some suitable answer with regular expression and arithmetic calculation, you can also try this
function myFunction() {
var str = 12.234556;
str = str.toString().split('.');
var res = str[1].slice(0, 2);
document.getElementById("demo").innerHTML = str[0]+'.'+res;
}
// output: 12.23
Here is what is did it with string
export function withoutRange(number) {
const str = String(number);
const dotPosition = str.indexOf('.');
if (dotPosition > 0) {
const length = str.substring().length;
const end = length > 3 ? 3 : length;
return str.substring(0, dotPosition + end);
}
return str;
}
Javascript has the function parseInt() which can help convert integer in a binary form into its decimal equivalent:
parseInt("101", 2) // 5
However, I need to convert binary fraction to its decimal equivalent, like:
0.101 = 0.625
I can write my own function that would calculate the result like the following:
1 * Math.pow(2, -1) + 0*Math.pow(2, -2) + 1*Math.pow(2, -3) // 0.625
But I'm wondering whether there is anything standard already.
This question asks whether there is some JavaScript standard for parsing binary floating-point numbers, as if parseFloat() could have taken a second radix parameter to parse the binary number 0.101 like this: parseFloat('0.101', 2).
While there is no such standard, there is an easy and direct way to solve this.
If we represent the binary number 0.101 as a binary fraction, it is easily converted to a decimal fraction:
0.1012 = 1012/10002 = (5/8)10 = 0.625
The following one-line expression translates this to JavaScript. Here, num could be any type of binary number (represented as a string), including negative numbers:
parseInt(num.replace('.', ''), 2) / Math.pow(2, (num.split('.')[1] || '').length)
The solution is easily adapted to floating-point numbers in any base between 2 and 36, and we can wrap it in our own parseFloatRadix() function:
function parseFloatRadix(num, radix) {
return parseInt(num.replace('.', ''), radix) /
Math.pow(radix, (num.split('.')[1] || '').length)
}
test('0.101', 2, 0.625);
test('0.011', 2, 0.375);
test('0.0011', 2, 0.1875);
test('-011', 2, -3);
test('011', 2, 3);
test('-1100.0011', 2, -12.1875);
test('1100.0011', 2, 12.1875);
test('0.00011001100110011001100', 2, 0.09999990463256836);
test('ABC', 16, 2748);
test('-0.DEF', 16, -0.870849609375);
test('ABC.DEF', 16, 2748.870849609375);
test('-102.201', 3, -11.703703703703704);
test('-Z.ZZZ', 36, -35.99997856652949);
function test(num, radix, expected){
let result = parseFloatRadix(num, radix);
console.log(num + ' (base ' + radix +') --> ' + result +
(result === expected ? ' (OK)' : ' (Expected ' + expected + ')'));
}
You can split the number (as string) at the dot and treat the integer part with an own function and the fraction part with another function for the right value.
The solution works with other bases as well.
function convert(value, base = 2) {
var [integer, fraction = ''] = value.toString().split('.');
return parseInt(integer, base) + (integer[0] !== '-' || -1) * fraction
.split('')
.reduceRight((r, a) => (r + parseInt(a, base)) / base, 0);
}
console.log(convert(1100)); // 12
console.log(convert(0.0011)); // 0.1875
console.log(convert(1100.0011)); // 12.1875
console.log(convert('ABC', 16)); // 2748
console.log(convert('0.DEF', 16)); // 0.870849609375
console.log(convert('ABC.DEF', 16)); // 2748.870849609375
console.log(convert('-ABC.DEF', 16)); // -2748.870849609375
console.log(convert(-1100.0011)); // -12.1875
.as-console-wrapper { max-height: 100% !important; top: 0; }
TL;DR:
const convert = (s, b) => (+((s = s.toString().trim().split("."))[0][0] !== "-") || -1) * ((parseInt(s[0].replace("-", ""), (b = +b || 2))) + (s[1].split("").reduceRight((n, d) => (n + parseInt(d, b)) / b, 0)));
Nina Scholz has a nice example, but it doesn't work with negative numbers (plus other issues).
So, this is an improved one:
/**
* #param {string} input
* #param {number} [base]
* #returns {number}
*/
function convert(input, base = 2) {
const [ integerRaw, decimalRaw = "" ] = input.toString().trim().split(".");
const integer = parseInt(integerRaw.replace("-", ""), base);
const decimal = decimalRaw.split("").reduceRight((sum, num) => (sum + parseInt(num, base)) / base, 0);
return (integerRaw.startsWith("-") ? -1 : 1) * (integer + decimal);
}
convert("1100.0011"); // 12.1875
convert("-1100.0011"); // -12.1875
convert("-Z.ZZZ", 36); // -35.99997856652949
As I know, JavaScript doesn't provide such built-in functionality.
But I'm wondering whether there is anything standard already.
No according my knowledge
I think you need to create your own function:
function toDecimal(string, radix) {
radix = radix || 2;
var s = string.split('.');
var decimal = parseInt(s[0], radix);
if(s.length > 1){
var fract = s[1].split('');
for(var i = 0, div = radix; i < fract.length; i++, div = div * radix) {
decimal = decimal + fract[i] / div;
}
}
return decimal;
}
You can create javascript extension method like parseInt as I have created method parseBinary which works just link parseInt.
String.prototype.parseBinary = function parseBinary() {
var radix = 2;
var s = this.split('.');
var decimal = parseInt(s[0], radix);
if(s.length > 1){
var fract = s[1].split('');
for(var i = 0, div = radix; i < fract.length; i++, div = div * radix)
{
decimal = decimal + fract[i] / div;
}
}
return decimal;
};
To use this method you can call it using following code.
var str = "0.101";
alert(str.parseBinary());
Here is a working example of javascript code
String.prototype.parseBinary = function parseBinary() {
var radix = 2;
var s = this.split('.');
var decimal = parseInt(s[0], radix);
if(s.length > 1){
var fract = s[1].split('');
for(var i = 0, div = radix; i < fract.length; i++, div = div * radix)
{
decimal = decimal + fract[i] / div;
}
}
return decimal;
};
var str = "0.101";
alert(str.parseBinary());
My logic behind is parseInt(res[0] + res[1], base) / Math.pow(base, res[1].length);
Ex :
var fValue = '-1100.0011';
var result= parseInt('-11000011', base) / Math.pow(base, '0011'.length);
<script>
parseFractionInt = (value, base = 2) => {
var res = value.split('.');
return res.length < 2 ?
parseInt(value, base) :
parseInt(res[0] + res[1], base) / Math.pow(base, res[1].length);
}
console.log(parseFractionInt('0.101')); //0.625
console.log(parseFractionInt('1100')); // 12
console.log(parseFractionInt('0.0011')); // 0.1875
console.log(parseFractionInt('1100.0011')); // 12.1875
console.log(parseFractionInt('ABC', 16)); // 2748
console.log(parseFractionInt('0.DEF', 16)); // 0.870849609375
console.log(parseFractionInt('ABC.DEF', 16)); // 2748.870849609375
console.log(parseFractionInt('-ABC.DEF', 16)); // -2748.870849609375
console.log(parseFractionInt('-1100.0011')); // -12.1875
console.log(parseFractionInt('G.G', 16)); //NaN
console.log(parseFractionInt('A.G', 16)); //0.625
</script>
What would be the best approach to creating a 8 character random password containing a-z, A-Z and 0-9?
Absolutely no security issues, this is merely for prototyping, I just want data that looks realistic.
I was thinking a for (0 to 7) Math.random to produce ASCII codes and convert them to characters. Do you have any other suggestions?
I would probably use something like this:
function generatePassword() {
var length = 8,
charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
retVal = "";
for (var i = 0, n = charset.length; i < length; ++i) {
retVal += charset.charAt(Math.floor(Math.random() * n));
}
return retVal;
}
That can then be extended to have the length and charset passed by a parameter.
Real Quick-n-dirtyâ„¢
Math.random().toString(36).slice(2, 10)
Voilà ! 8 random alphanumeric characters.
The idea is to cast a random number (in the range 0..1) to a base36 string (lowercase a-z plus 0-9), and then fetch the first 8 characters after the leading zero and decimal point.
However, please be aware that different browsers and javascript implementations used to give different bit depth results for Math.random(). If you are running in an old pre-2016 chrome or pre-2017 safari browser, this might mean (in worst case scenario) you get a shorter password than 8 characters. Though, you could solve this by simply concatenating two strings, and then slice it back down to 8 characters again.
A better solution
Though, please be aware that Math.random() was never designed or meant to be cryptographically secure. Since you only want passwords 8 characters long, I assume you're not interested in this in any case. However, for reference (and everyone else), I'll show a solution based on an actual CSPRNG. The idea is the same, we're just utilizing window.crypto instead.
window.crypto.getRandomValues(new BigUint64Array(1))[0].toString(36)
Here we are generating 1 word with 64 bits of random data, and cast it to a base36 string (0-9 and a-z). It should give you a truly random string roughly 10-13 characters long.
Extending the solution
However, to make it more secure we also want it to be longer and with mixed upper and lower cases.
We could do this either by just repeating the process twice:
let strings = window.crypto.getRandomValues(new BigUint64Array(2));
console.log(strings[0].toString(36) + strings[1].toString(36).toUpperCase());
Or we could make a fancy generic generator which uses Array.reduce to concatenate multiple random 64 bit words, alternating between uppercasing each stanza:
window.crypto.getRandomValues(new BigUint64Array(length)).reduce(
(prev, curr, index) => (
!index ? prev : prev.toString(36)
) + (
index % 2 ? curr.toString(36).toUpperCase() : curr.toString(36)
)
);
length is the number of 64 bit words to join. I generally use 4, which gives me rougly 48-52 random alphanumeric characters, upper and lower cased.
If you specifically want "special characters" included, you can optionally replace the 0-9 numbers in the uppercase stanzas with a simple replace() call.
const regx = new RegExp(/\d/, "g");
window.crypto.getRandomValues(new BigUint64Array(length)).reduce(
(prev, curr, index) => (
!index ? prev : prev.toString(36)
) + (
index % 2 ? curr.toString(36).toUpperCase().replace(regx, key => ".,:;-_()=*".charAt(key)) : curr.toString(36)
)
);
You may also optionally shuffle the final order, which is easily accomplished with this chaining "oneliner"
password.split('').sort(
() => 128 - window.crypto.getRandomValues(new Uint8Array(1))[0]
).join('')
The idea here is to split the generated string into an array of characters, and then sort that character array with cryptographical randomness, and finally joining it back into a string.
Personally, I have this little bookmarklet saved in my browser bookmarks bar, for quick and easy access whenever I need to generate a site-specific username:
javascript:(
function(){
prompt('Here is your shiny new random string:',
window.crypto.getRandomValues(new BigUint64Array(4)).reduce(
(prev, curr, index) => (
!index ? prev : prev.toString(36)
) + (
index % 2 ? curr.toString(36).toUpperCase() : curr.toString(36)
)
).split('').sort(() => 128 -
window.crypto.getRandomValues(new Uint8Array(1))[0]
).join('')
);
}
)();
Compatibility notices
BigUint64Array was added in:
Chrome/Chromium 67 in May 2018
Node 10.4 in June 2018
Firefox 68 in July 2019
Edge 79 in January 2020 (the first stable Chromium-based Edge release)
The final ECMAScript 2020 specification (ES11) in June 2020
and finally Safari 15 in September 2021.
Other JS engines are tracked on Can I Use or MDN Compatibility Table
Crypto.getRandomValues() has better support (except for Node):
Chrome 11
Edge 12
Firefox 21
Safari 5
Node 15.0
So if you're still on team IE 11 or use end-of-life node versions, you're stuck with using a polyfill, math.round() or a workaround with other types such as BigUInt32Array.
function password_generator( len ) {
var length = (len)?(len):(10);
var string = "abcdefghijklmnopqrstuvwxyz"; //to upper
var numeric = '0123456789';
var punctuation = '!##$%^&*()_+~`|}{[]\:;?><,./-=';
var password = "";
var character = "";
var crunch = true;
while( password.length<length ) {
entity1 = Math.ceil(string.length * Math.random()*Math.random());
entity2 = Math.ceil(numeric.length * Math.random()*Math.random());
entity3 = Math.ceil(punctuation.length * Math.random()*Math.random());
hold = string.charAt( entity1 );
hold = (password.length%2==0)?(hold.toUpperCase()):(hold);
character += hold;
character += numeric.charAt( entity2 );
character += punctuation.charAt( entity3 );
password = character;
}
password=password.split('').sort(function(){return 0.5-Math.random()}).join('');
return password.substr(0,len);
}
console.log( password_generator() );
This generates a little more robust password that should pass any password strength test. eg: f1&d2?I4(h1&, C1^y1)j1#G2#, j2{h6%b5#R2)
This is my function for generating a 8-character crypto-random password:
function generatePassword() {
var buf = new Uint8Array(6);
window.crypto.getRandomValues(buf);
return btoa(String.fromCharCode.apply(null, buf));
}
What it does: Retrieves 6 crypto-random 8-bit integers and encodes them with Base64.
Since the result is in the Base64 character set the generated password may consist of A-Z, a-z, 0-9, + and /.
function generatePass(pLength){
var keyListAlpha="abcdefghijklmnopqrstuvwxyz",
keyListInt="123456789",
keyListSpec="!##_",
password='';
var len = Math.ceil(pLength/2);
len = len - 1;
var lenSpec = pLength-2*len;
for (i=0;i<len;i++) {
password+=keyListAlpha.charAt(Math.floor(Math.random()*keyListAlpha.length));
password+=keyListInt.charAt(Math.floor(Math.random()*keyListInt.length));
}
for (i=0;i<lenSpec;i++)
password+=keyListSpec.charAt(Math.floor(Math.random()*keyListSpec.length));
password=password.split('').sort(function(){return 0.5-Math.random()}).join('');
return password;
}
code to generate a password with a given length (default to 8) and have at least one upper case, one lower, one number and one symbol
(2 functions and one const variable called 'Allowed')
const Allowed = {
Uppers: "QWERTYUIOPASDFGHJKLZXCVBNM",
Lowers: "qwertyuiopasdfghjklzxcvbnm",
Numbers: "1234567890",
Symbols: "!##$%^&*"
}
const getRandomCharFromString = (str) => str.charAt(Math.floor(Math.random() * str.length))
/**
* the generated password will be #param length, which default to 8,
* and will have at least one upper, one lower, one number and one symbol
* #param {number} length - password's length
* #returns a generated password
*/
const generatePassword = (length = 8) => {
let pwd = "";
pwd += getRandomCharFromString(Allowed.Uppers); // pwd will have at least one upper
pwd += getRandomCharFromString(Allowed.Lowers); // pwd will have at least one lower
pwd += getRandomCharFromString(Allowed.Numbers); // pwd will have at least one number
pwd += getRandomCharFromString(Allowed.Symbols); // pwd will have at least one symbol
for (let i = pwd.length; i < length; i++)
pwd += getRandomCharFromString(Object.values(Allowed).join('')); // fill the rest of the pwd with random characters
return pwd
}
A modern and secure solution
Be aware of answers that rely on Math.random - they are not secure. This is an old question so it's no surprise that Math.random still pops up, but you should absolutely not be using it to generate a string to secure anything. If you really need to support browsers older than IE11, you should add a fallback to get the random values from the back-end, generated using a CSPRNG.
function generatePassword(length) {
const crypto = window.crypto || window.msCrypto;
if (typeof crypto === 'undefined') {
throw new Error('Crypto API is not supported. Please upgrade your web browser');
}
const charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
const indexes = crypto.getRandomValues(new Uint32Array(length));
let secret = '';
for (const index of indexes) {
secret += charset[index % charset.length];
}
return secret;
}
This is a simple example. You'd probably want to add special characters to the set and maybe enforce digits or symbols to be present.
If you have lodash >= 4.0 in place there is a more elegant way of doing it
var chars = 'abcdefghkmnpqrstuvwxyz23456789';
function generatePassword(length) {
return _.sampleSize(chars, length).join('');
}
Here's my take (with Typescript) on this using the browser crypto API and enforcing a password which has at least:
1 lower case letter
1 upper case letter
1 symbol
const LOWER_CASE_CHARS = 'abcdefghijklmnopqrstuvwxyz'.split('');
const UPPER_CASE_CHARS = LOWER_CASE_CHARS.map((x) => x.toUpperCase());
const SYMBOLS = '!£$%^&*()#~:;,./?{}=-_'.split('');
const LETTERS_MIX = [...LOWER_CASE_CHARS, ...UPPER_CASE_CHARS, ...SYMBOLS];
const CHARS_LENGTH = LETTERS_MIX.length;
function containsLowerCase(str: string): boolean {
return LOWER_CASE_CHARS.some((x) => str.includes(x));
}
function containsUpperCase(str: string): boolean {
return UPPER_CASE_CHARS.some((x) => str.includes(x));
}
function containsSymbol(str: string): boolean {
return SYMBOLS.some((x) => str.includes(x));
}
function isValidPassword(password: string) {
return containsLowerCase(password) && containsUpperCase(password) && containsSymbol(password);
}
export function generateStrongPassword(length: number = 16): string {
const buff = new Uint8Array(length);
let generatedPassword = '';
do {
window.crypto.getRandomValues(buff);
generatedPassword = [...buff].map((x) => LETTERS_MIX[x % CHARS_LENGTH]).join('');
} while (!isValidPassword(generatedPassword));
return generatedPassword;
}
This will produce a realistic password if having characters [\]^_ is fine. Requires lodash and es7
String.fromCodePoint(...range(8).map(() => Math.floor(Math.random() * 57) + 0x41))
and here's without lodash
String.fromCodePoint(...Array.from({length: 8}, () => Math.floor(Math.random() * 57) + 65))
Here is a function provides you more options to set min of special chars, min of upper chars, min of lower chars and min of number
function randomPassword(len = 8, minUpper = 0, minLower = 0, minNumber = -1, minSpecial = -1) {
let chars = String.fromCharCode(...Array(127).keys()).slice(33),//chars
A2Z = String.fromCharCode(...Array(91).keys()).slice(65),//A-Z
a2z = String.fromCharCode(...Array(123).keys()).slice(97),//a-z
zero2nine = String.fromCharCode(...Array(58).keys()).slice(48),//0-9
specials = chars.replace(/\w/g, '')
if (minSpecial < 0) chars = zero2nine + A2Z + a2z
if (minNumber < 0) chars = chars.replace(zero2nine, '')
let minRequired = minSpecial + minUpper + minLower + minNumber
let rs = [].concat(
Array.from({length: minSpecial ? minSpecial : 0}, () => specials[Math.floor(Math.random() * specials.length)]),
Array.from({length: minUpper ? minUpper : 0}, () => A2Z[Math.floor(Math.random() * A2Z.length)]),
Array.from({length: minLower ? minLower : 0}, () => a2z[Math.floor(Math.random() * a2z.length)]),
Array.from({length: minNumber ? minNumber : 0}, () => zero2nine[Math.floor(Math.random() * zero2nine.length)]),
Array.from({length: Math.max(len, minRequired) - (minRequired ? minRequired : 0)}, () => chars[Math.floor(Math.random() * chars.length)]),
)
return rs.sort(() => Math.random() > Math.random()).join('')
}
randomPassword(12, 1, 1, -1, -1)// -> DDYxdVcvIyLgeB
randomPassword(12, 1, 1, 1, -1)// -> KYXTbKf9vpMu0
randomPassword(12, 1, 1, 1, 1)// -> hj|9)V5YKb=7
Gumbo's solution does not work. This one does though:
function makePasswd() {
var passwd = '';
var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
for (i=1;i<8;i++) {
var c = Math.floor(Math.random()*chars.length + 1);
passwd += chars.charAt(c)
}
return passwd;
}
Randomly assigns Alpha, Numeric, Caps and Special per character then validates the password. If it doesn't contain each of the above, randomly assigns a new character from the missing element to a random existing character then recursively validates until a password is formed:
function createPassword(length) {
var alpha = "abcdefghijklmnopqrstuvwxyz";
var caps = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var numeric = "0123456789";
var special = "!$^&*-=+_?";
var options = [alpha, caps, numeric, special];
var password = "";
var passwordArray = Array(length);
for (i = 0; i < length; i++) {
var currentOption = options[Math.floor(Math.random() * options.length)];
var randomChar = currentOption.charAt(Math.floor(Math.random() * currentOption.length));
password += randomChar;
passwordArray.push(randomChar);
}
checkPassword();
function checkPassword() {
var missingValueArray = [];
var containsAll = true;
options.forEach(function (e, i, a) {
var hasValue = false;
passwordArray.forEach(function (e1, i1, a1) {
if (e.indexOf(e1) > -1) {
hasValue = true;
}
});
if (!hasValue) {
missingValueArray = a;
containsAll = false;
}
});
if (!containsAll) {
passwordArray[Math.floor(Math.random() * passwordArray.length)] = missingValueArray.charAt(Math.floor(Math.random() * missingValueArray.length));
password = "";
passwordArray.forEach(function (e, i, a) {
password += e;
});
checkPassword();
}
}
return password;
}
I see much examples on this page are using Math.random. This method hasn't cryptographically strong random values so it's unsecure. Instead Math.random recomended use getRandomValues or your own alhorytm.
You can use passfather. This is a package that are using much cryptographically strong alhorytmes. I'm owner of this package so you can ask some question.
passfather
I got insprired by the answers above (especially by the hint from #e.vyushin regarding the security of Math.random() ) and I came up with the following solution that uses the crypto.getRandomValues() to generate a rondom array of UInt32 values with the length of the password length.
Then, it loops through the array and devides each element by 2^32 (max value of a UInt32) to calculate the ratio between the actual value and the max. possible value. This ratio is then mapped to the charset string to determine which character of the string is picked.
console.log(createPassword(16,"letters+numbers+signs"));
function createPassword(len, charset) {
if (charset==="letters+numbers") {
var chars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
} else if (charset==="letters+numbers+signs") {
var chars = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!§$%&/?#+-_#";
}
var arr = new Uint32Array(len);
var maxRange = Math.pow(2,32);
var passwd = '';
window.crypto.getRandomValues(arr);
for (let i=0;i<len;i++) {
var c = Math.floor(arr[i] / maxRange * chars.length + 1);
passwd += chars.charAt(c);
}
return passwd;
}
Thus, the code is able to use the advantage of the crypto-Class (improved security for the random value generation) and is adaptable to use any kind of charset the user wished. A next step would be to use regular expression strings to define the charset to be used.
Generate a random password of length 8 to 32 characters with at least 1 lower case, 1 upper case, 1 number, 1 special char (!#$&)
function getRandomUpperCase() {
return String.fromCharCode( Math.floor( Math.random() * 26 ) + 65 );
}
function getRandomLowerCase() {
return String.fromCharCode( Math.floor( Math.random() * 26 ) + 97 );
}
function getRandomNumber() {
return String.fromCharCode( Math.floor( Math.random() * 10 ) + 48 );
}
function getRandomSymbol() {
// const symbol = '!##$%^&*(){}[]=<>/,.|~?';
const symbol = '!#$&';
return symbol[ Math.floor( Math.random() * symbol.length ) ];
}
const randomFunc = [ getRandomUpperCase, getRandomLowerCase, getRandomNumber, getRandomSymbol ];
function getRandomFunc() {
return randomFunc[Math.floor( Math.random() * Object.keys(randomFunc).length)];
}
function generatePassword() {
let password = '';
const passwordLength = Math.random() * (32 - 8) + 8;
for( let i = 1; i <= passwordLength; i++ ) {
password += getRandomFunc()();
}
//check with regex
const regex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$!%*?&])[A-Za-z\d#$!%*?&]{8,32}$/
if( !password.match(regex) ) {
password = generatePassword();
}
return password;
}
console.log( generatePassword() );
here is a simply smart code :
function generate(l) {
if (typeof l==='undefined'){var l=8;}
/* c : alphanumeric character string */
var c='abcdefghijknopqrstuvwxyzACDEFGHJKLMNPQRSTUVWXYZ12345679',
n=c.length,
/* p : special character string */
p='!##$+-*&_',
o=p.length,
r='',
n=c.length,
/* s : determinate the position of the special character */
s=Math.floor(Math.random() * (p.length-1));
for(var i=0; i<l; ++i){
if(s == i){
/* special charact insertion (random position s) */
r += p.charAt(Math.floor(Math.random() * o));
}else{
/* alphanumeric insertion */
r += c.charAt(Math.floor(Math.random() * n));
}
}
return r;
}
Simply call generate(), and it do key containing one special character (!##$+-*&_) for security.
Possible results : WJGUk$Ey, gaV7#fF7, ty_T55DD, YtrQMWveZqYyYKo_
There is more details and example in my website : https://www.bxnxg.com/minituto-01-generer-mots-de-passes-secures-facilements-en-javascript/
Stop the madness!
My pain point is that every Sign-Up tool allows a different set of special characters. Some might only allow these ##$%&* while others maybe don't allow * but do allow other things. Every password generator I've come across is binary when it comes to special characters. It allows you to either include them or not. So I wind up cycling through tons of options and scanning for outliers that don't meet the requirements until I find a password that works. The longer the password the more tedious this becomes. Finally, I have noticed that sometimes Sign-Up tools don't let you repeat the same character twice in a row but password generators don't seem to account for this. It's madness!
I made this for myself so I can just paste in the exact set of special characters that are allowed. I do not pretend this is elegant code. I just threw it together to meet my needs.
Also, I couldn't think of a time when a Sign-Up tool did not allow numbers or wasn't case sensitive so my passwords always have at least one number, one upper case letter, one lower case letter, and one special character. This means the minimum length is 4. Technically I can get around the special character requirement by just entering a letter if need be.
const getPassword = (length, arg) => {
length = document.getElementById("lengthInput").value || 16;
arg = document.getElementById("specialInput").value || "~!##$%^&*()_+-=[]{}|;:.,?><";
if (length < 4) {
updateView("passwordValue", "passwordValue", "", "P", "Length must be at least 4");
return console.error("Length must be at least 4")
} else if (length > 99) {
updateView("passwordValue", "passwordValue", "", "P", "Length must be less then 100");
return console.error("Length must be less then 100")
}
const lowercase = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
const uppercase = lowercase.join("").toUpperCase().split("");
const specialChars = arg.split("").filter(item => item.trim().length);
const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let hasNumber = false;
let hasUpper = false;
let hasLower = false;
let hasSpecial = false;
if (Number(length)) {
length = Number(length)
} else {
return console.error("Enter a valid length for the first argument.")
}
let password = [];
let lastChar;
for (let i = 0; i < length; i++) {
let char = newChar(lowercase, uppercase, numbers, specialChars);
if (char !== lastChar) {
password.push(char);
lastChar = char
if (Number(char)) {
hasNumber = true
}
if (lowercase.indexOf(char) > -1) {
hasLower = true
}
if (uppercase.indexOf(char) > -1) {
hasUpper = true
}
if (specialChars.indexOf(char) > -1) {
hasSpecial = true
}
} else {
i--
}
if (i === length - 1 && (!hasNumber || !hasUpper || !hasLower || !hasSpecial)) {
hasNumber = false;
hasUpper = false;
hasLower = false;
hasSpecial = false;
password = [];
i = -1;
}
}
function newChar(lower, upper, nums, specials) {
let set = [lower, upper, nums, specials];
let pick = set[Math.floor(Math.random() * set.length)];
return pick[Math.floor(Math.random() * pick.length)]
}
updateView("passwordValue", "passwordValue", "", "P", password.join(""));
updateView("copyPassword", "copyPassword", "", "button", "copy text");
document.getElementById("copyPassword").addEventListener("click", copyPassword);
}
const copyPassword = () => {
let text = document.getElementById("passwordValue").textContent;
navigator.clipboard.writeText(text);
};
const updateView = (targetId, newId, label, element, method = '') => {
let newElement = document.createElement(element);
newElement.id = newId;
let content = document.createTextNode(label + method);
newElement.appendChild(content);
let currentElement = document.getElementById(targetId);
let parentElement = currentElement.parentNode;
parentElement.replaceChild(newElement, currentElement);
}
document.getElementById("getPassword").addEventListener("click", getPassword);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div>
<button id="getPassword">Generate Password</button>
<input type="number" id="lengthInput" placeholder="Length">
<input type="text" id="specialInput" placeholder="Special Characters">
<p id="passwordValue"></p>
<p id="copyPassword"></p>
</div>
</body>
</html>
even shorter:
Array.apply(null, Array(8)).map(function() {
var c = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
return c.charAt(Math.random() * c.length);
}).join('');
or as function:
function generatePassword(length, charSet) {
charSet = charSet ? charSet : 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789^°!"§$%&/()=?`*+~\'#,;.:-_';
return Array.apply(null, Array(length || 10)).map(function() {
return charSet.charAt(Math.random() * charSet.length);
}).join('');
}
function genPass(n) // e.g. pass(10) return 'unQ0S2j9FY'
{
let c='abcdefghijklmnopqrstuvwxyz'; c+=c.toUpperCase()+1234567890;
return [...Array(n)].map(b=>c[~~(Math.random()*62)]).join('')
}
Where n is number of output password characters; 62 is c.length and where e.g. ~~4.5 = 4 is trick for replace Math.floor
Alternative
function genPass(n) // e.g. pass(10) return 'unQ0S2j9FY'
{
let c='abcdefghijklmnopqrstuvwxyz'; c+=c.toUpperCase()+1234567890;
return '-'.repeat(n).replace(/./g,b=>c[~~(Math.random()*62)])
}
to extend characters list, add them to c e.g. to add 10 characters !$^&*-=+_? write c+=c.toUpperCase()+1234567890+'!$^&*-=+_?' and change Math.random()*62 to Math.random()*72 (add 10 to 62).
This method gives the options to change size and charset of your password.
function generatePassword(length=8, charset="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
return new Array(length)
.fill(null)
.map(()=> charset.charAt(Math.floor(Math.random() * charset.length)))
.join('');
}
console.log(generatePassword()); // 02kdFjzX
console.log(generatePassword(4)); // o8L5
console.log(generatePassword(16)); // jpPd7S09txv9b02p
console.log(generatePassword(16, "abcd1234")); // 4c4d323a31c134dd
A simple lodash solution that warranties 14 alpha, 3 numeric and 3 special characters, not repeated:
const generateStrongPassword = (alpha = 14, numbers = 3, special = 3) => {
const alphaChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numberChars = '0123456789';
const specialChars = '!"£$%^&*()-=+_?';
const pickedChars = _.sampleSize(alphaChars, alpha)
.concat(_.sampleSize(numberChars, numbers))
.concat(_.sampleSize(specialChars, special));
return _.shuffle(pickedChars).join('');
}
const myPassword = generateStrongPassword();
I also developed my own password generator, with random length (between 16 and 40 by default), strong passwords, maybe it could help.
function randomChar(string) {
return string[Math.floor(Math.random() * string.length)];
}
// you should use another random function, like the lodash's one.
function random(min = 0, max = 1) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// you could use any shuffle function, the lodash's one, or the following https://stackoverflow.com/a/6274381/6708504
function shuffle(a) {
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
function generatePassword() {
const symbols = '§±!##$%^&*()-_=+[]{}\\|?/<>~';
const numbers = '0123456789';
const lowercaseLetters = 'abcdefghijklmnopqrstuvwxyz';
const uppercaseLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const minCharsGroup = 4;
const maxCharsGroup = 10;
const randomSymbols = [...Array(random(minCharsGroup, maxCharsGroup))].map(() => randomChar(symbols));
const randomNumbers = [...Array(random(minCharsGroup, maxCharsGroup))].map(() => randomChar(numbers));
const randomUppercasesLetters = [...Array(random(minCharsGroup, maxCharsGroup))].map(() => randomChar(uppercaseLetters));
const randomLowercasesLetters = [...Array(random(minCharsGroup, maxCharsGroup))].map(() => randomChar(lowercaseLetters));
const chars = [...randomSymbols, ...randomNumbers, ...randomUppercasesLetters, ...randomLowercasesLetters];
return shuffle(chars).join('');
}
const alpha = 'abcdefghijklmnopqrstuvwxyz';
const calpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const num = '1234567890';
const specials = ',.!##$%^&*';
const options = [alpha, alpha, alpha, calpha, calpha, num, num, specials];
let opt, choose;
let pass = "";
for ( let i = 0; i < 8; i++ ) {
opt = Math.floor(Math.random() * options.length);
choose = Math.floor(Math.random() * (options[opt].length));
pass = pass + options[opt][choose];
options.splice(opt, 1);
}
console.log(pass);
Length 8 characters
At least 1 Capital
At least 1 Number
At least 1 Special Character
Here's another approach based off Stephan Hoyer's solution
var _ = require('lodash');
function getRandomString(length) {
var chars = 'abcdefghkmnpqrstuvwxyz23456789';
return _.times(length, () => sample(chars)).join('');
}
Update: replacing the core Math.random() by crypto.getRandomValues and add options
Solution with scrambling:
const Allowed = {
Uppers: 'QWERTYUIOPASDFGHJKLZXCVBNM',
Lowers: 'qwertyuiopasdfghjklzxcvbnm',
Numbers: '1234567890',
Symbols: '!##$%^&*'
}
const AllowedUpperArray = Array.from(Allowed.Uppers)
const AllowedLowerArray = Array.from(Allowed.Lowers)
const AllowedNumberArray = Array.from(Allowed.Numbers)
const AllowedSymbolArray = Array.from(Allowed.Symbols)
function getCharAt(charArray, index) {
return charArray[index % charArray.length]
}
function scrambleArray(chars) {
return chars.sort(() => Math.random() - 0.5)
}
function getAllowedChars(compositionRule = {}) {
let chars = []
if (!compositionRule.upperCase?.forbidden) chars = chars.concat(AllowedUpperArray)
if (!compositionRule.lowerCase?.forbidden) chars = chars.concat(AllowedLowerArray)
if (!compositionRule.numbers?.forbidden) chars = chars.concat(AllowedNumberArray)
if (!compositionRule.symbols?.forbidden) chars = chars.concat(AllowedSymbolArray)
return chars
}
function assertAreRulesValid(compositionRule) {
const {
upperCase,
lowerCase,
numbers,
symbols
} = compositionRule
if (length < 1) throw new Error('length < 1')
if (upperCase?.min < 0) throw new Error('upperCase.min < 0')
if (lowerCase?.min < 0) throw new Error('lowerCase.min < 0')
if (numbers?.min < 0) throw new Error('numbers.min < 0')
if (symbols?.min < 0) throw new Error('symbols.min < 0')
if (length && length < (upperCase?.min || 0 + lowerCase?.min || 0 + numbers?.min || 0 + symbols?.min || 0)) throw new Error('length < sum of min')
if (upperCase?.forbidden && lowerCase?.forbidden && numbers?.forbidden && symbols?.forbidden) throw new Error('no char type allowed')
if (upperCase?.forbidden && upperCase?.min) throw new Error('forbidden incompatible with min')
if (lowerCase?.forbidden && lowerCase?.min) throw new Error('forbidden incompatible with min')
if (symbols?.forbidden && symbols?.min) throw new Error('forbidden incompatible with min')
if (numbers?.forbidden && numbers?.min) throw new Error('forbidden incompatible with min')
}
/**
* Generates password of the given length with at least one upper, one lower, one number and one symbol.
* #param length length of the password, min 4
* #throws Error if length is less than 4
*/
function generatePassword(length = 8, compositionRule = {}) {
const {
upperCase,
lowerCase,
numbers,
symbols
} = compositionRule
const indexes = crypto.getRandomValues(new Uint32Array(length));
const chars = []
let i = 0
let lastIndex = i
while (i < upperCase?.min || 0) chars.push(getCharAt(AllowedUpperArray, indexes[i++]))
while (i < lastIndex + lowerCase?.min || 0) chars.push(getCharAt(AllowedLowerArray, indexes[i++]))
lastIndex = i
while (i < lastIndex + numbers?.min || 0) chars.push(getCharAt(AllowedNumberArray, indexes[i++]))
lastIndex = i
while (i < lastIndex + symbols?.min || 0) chars.push(getCharAt(AllowedSymbolArray, indexes[i++]))
const allowedChars = getAllowedChars(compositionRule)
while (i < length || 0) chars.push(getCharAt(allowedChars, indexes[i++]))
return scrambleArray(chars).join('')
}
const opt1 = {
upperCase: { min: 3 },
lowerCase: { forbidden: true },
numbers: { min: 2 },
symbols: { min: 1 }
}
const pwd1 = generatePassword(10, opt1)
console.log('10 characters, min 3 uppercase, 2 numbers, 1 symbol and no lowercase:', pwd1)
const opt2 = {
upperCase: { forbidden: true },
lowerCase: { forbidden: true },
numbers: { forbidden: true },
symbols: { min: 1 }
}
const pwd2 = generatePassword(5, opt2)
console.log('5 characters, min 1 symbol but upperCase, lowercase, and numbers forbidden:', pwd2)
Answers so far are overly complicated or use Math.random() or depend on another package.
I feel the world needs yet another password generator :-)
/**
* #param {number} length
* #returns {string}
*/
function generateRandomPassword(length) {
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
return window.crypto.getRandomValues(new Uint8Array(length)).reduce((password, number) => {
return password + charset.charAt(number % charset.length);
}, "");
}
Valid characters are fixed but can be trivially tailored. Probability of having a digit can be increased by repeating the sequence in the charset (i.e: charset = "…vwxyz01234567890123456789").
It uses the secure getRandomValues().
It doesn't ensure the password contains at least one uppercase letter, one lowercase letter and one digit. Therefore, it might generate a real word/noun or even an offensive word. It is very unlikely with longer passwords, though. Skewing toward digits (as explained above) may not solve that issue due to l33t. Adding some special characters is the safest course if that is your concern.
PS: Should charset be more than 256 characters long, the code must use Uint16Array instead.
PPS: What's wrong with Math.random(): it is pseudo-random. The sequence is somewhat predictable. Not every possible theoretical password can be generated because the next character is determined from a computed sequence.
Here's a free, configurable Javascript class generating random passwords: Javascript Random Password Generator.
Examples
Password consisting of Lower case + upper case + numbers, 8 characters long:
var randomPassword = new RandomPassword();
document.write(randomPassword.create());
Password consisting of Lower case + upper case + numbers, 20 characters long:
var randomPassword = new RandomPassword();
document.write(randomPassword.create(20));
Password consisting of Lower case + upper case + numbers + symbols, 20 characters long:
var randomPassword = new RandomPassword();
document.write(randomPassword.create(20,randomPassword.chrLower+randomPassword.chrUpper+randomPassword.chrNumbers+randomPassword.chrSymbols));
var createPassword = function() {
var passAt = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
var passArray = Array.from({length: 15})
return passArray.map(function(_, index) {
return index % 4 == 3 ? '-' : passAt.charAt(Math.random() * passAt.length)
}).join('')
}
result like:
L5X-La0-bN0-UQO
9eW-svG-OdS-8Xf
ick-u73-2s0-TMX
5ri-PRP-MNO-Z1j
Here's a quick dynamic modern solution which I thought I'll share
const generatePassword = (
passwordLength = 8,
useUpperCase = true,
useNumbers = true,
useSpecialChars = true,
) => {
const chars = 'abcdefghijklmnopqrstuvwxyz'
const numberChars = '0123456789'
const specialChars = '!"£$%^&*()'
const usableChars = chars
+ (useUpperCase ? chars.toUpperCase() : '')
+ (useNumbers ? numberChars : '')
+ (useSpecialChars ? specialChars : '')
let generatedPassword = ''
for(i = 0; i <= passwordLength; i++) {
generatedPassword += usableChars[Math.floor(Math.random() * (usableChars.length))]
}
return generatedPassword
}