Javascript equivalent of Java's UUID class - javascript

In java, you can do something like
UUID id = UUID.fromString("eb66c416-4739-465b-9af3-9dc33ed8eef9");
long msb = id.getMostSignificantBits();
long lsb = id.getLeastSignificantBits();
System.out.println(msb + ", " + lsb);
// -1484283427208739237, -7281302710629372167
System.out.println(new UUID(msb, lsb));
// eb66c416-4739-465b-9af3-9dc33ed8eef9
This same example is referenced in another question which is pretty similar, so this would be a follow up. While in the related question problem of lsb, msb -> string was solved, I cannot find solution for reverse problem, string -> msb, lsb
The original solution was
function toUuidString(lsb, msb) {
return `${digits(msb >> 32n, 8n)}-${digits(msb >> 16n, 4n)}-${digits(
msb,
4n
)}-${digits(lsb >> 48n, 4n)}-${digits(lsb, 12n)}`
}
function digits(value, ds) {
const hi = 1n << (ds * 4n)
return (hi | (value & (hi - 1n))).toString(16).slice(1)
}
Now I'd like to have a function that takes in string and returns msb and lsb.
Following original questions' paths, I've discovered java source code and tried to do the equivalent, which would be:
function fromString(name) {
let components = name.split('-')
if (components.length !== 5) {
throw new Error(`Invalid UUID string: ${name}`)
}
for (let index = 0; index < 5; index++) {
components[index] = `0x${components[index]}`
}
let mostSigBits = Number.parseInt(components[0], 16)
mostSigBits <<= 16
mostSigBits |= Number.parseInt(components[1], 16)
mostSigBits <<= 16
mostSigBits |= Number.parseInt(components[2], 16)
let leastSigBits = Number.parseInt(components[3], 16)
leastSigBits <<= 48
leastSigBits |= Number.parseInt(components[4], 16)
return {
leastSigBits,
mostSigBits,
}
}
However, when I try to test this with something like:
const originalUuid = 'eb66c416-4739-465b-9af3-9dc33ed8eef9'
const parts = fromString(originalUuid)
const newUUid = toUuidString(
BigInt(parts.leastSigBits),
BigInt(parts.mostSigBits)
)
console.log('Original', originalUuid)
console.log('New', newUUid)
I do not get equivalent uuids. They have equivalent parts but some parts are missing
Original eb66c416-4739-465b-9af3-9dc33ed8eef9
New 00000000-4739-465b-ffff-ffffbefbeef9
Any ideas what went wrong?

Finally I found the problem - two codes were not strictly equivalent, java source code declared mostSigBits and leastSigBits as long, which cannot be represented in javascript, so we need to use BigInt.
To sum up my question and previous question, javascript equivalent for java's UUID operations would be:
string -> msb, lsb
function fromString(name) {
let components = name.split('-')
if (components.length !== 5) {
throw new Error(`Invalid UUID string: ${name}`)
}
for (let index = 0; index < 5; index++) {
components[index] = `0x${components[index]}`
}
let mostSigBits = BigInt(Number.parseInt(components[0], 16))
mostSigBits <<= 16n
mostSigBits |= BigInt(Number.parseInt(components[1], 16))
mostSigBits <<= 16n
mostSigBits |= BigInt(Number.parseInt(components[2], 16))
let leastSigBits = BigInt(Number.parseInt(components[3], 16))
leastSigBits <<= 48n
leastSigBits |= BigInt(Number.parseInt(components[4], 16))
return {
leastSigBits,
mostSigBits,
}
}
msb, lsb -> string (from the referenced question)
function toUuidString(lsb, msb) {
return `${digits(msb >> 32n, 8n)}-${digits(msb >> 16n, 4n)}-${digits(
msb,
4n
)}-${digits(lsb >> 48n, 4n)}-${digits(lsb, 12n)}`
}
function digits(value, ds) {
const hi = 1n << (ds * 4n)
return (hi | (value & (hi - 1n))).toString(16).slice(1)
}

Related

Hash algorithm issue with converting code from javascript to python

To get same hash function in javascript and python I tried to convert my javaScript function to python and completely stack with gooooogle int as result in python variant.
javascript
function str_hash(var s) {
var hash = 0, i, chr;
if (s.length === 0) return hash;
for (i = 0; i < s.length; i++)
{
chr = s.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
return hash;
};
output is like: -34998534 whatever
my python try:
def get_hash(s):
h = 0
if not s:
return h
for i in range(0, len(s)):
h = ((h << 5) - h) + i
h |= 0
return h
print(get_hash('PUT LONG STRING HERE'))
output is like: 349832894283058945028049523548405975892375489743847490218348927483984793048218934148973940218340298489273942374902938490238482942930729487210948239407329403082738940214 whatever
Any ideas how to fix it?
here is the python equivalent code
def str_hash(s):
hash = 0
for i in range(len(s)):
chr = ord(s[i])
hash = ((hash << 5) - hash) + chr
hash = hash & 0xFFFFFFFF
return hash
print(str_hash("PUT LONG STRING HERE"))
the << operator in javascript is called the bitwise left shift operator. and the native code for this is explained in the below example
let num = 4
let shiftBy = 2
print(num * 2 ** shiftBy) // num * Math.pow(2,shiftBy)
print(num << shiftBy)

Using bitwise operators with large numbers in javascript [duplicate]

This question already has answers here:
Bitshift in javascript
(4 answers)
Closed 3 years ago.
I am writing a Javascript version of this Microsoft string decoding algorithm and its failing on large numbers. This seems to be because of sizing (int / long) issues. If I step through the code in C# I see that the JS implementation fails on this line
n |= (b & 31) << k;
This happens when the values are (and the C# result is 240518168576)
(39 & 31) << 35
If I play around with these values in C# I can replicate the JS issue if b is an int. And If I set b to be long it works correctly.
So then I checked the max size of a JS number, and compared it to the C# long result
240518168576 < Number.MAX_SAFE_INTEGER = true
So.. I can see that there is some kind of number size issue happening but do not know how to force JS to treat this number as a long.
Full JS code:
private getPointsFromEncodedString(encodedLine: string): number[][] {
const EncodingString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
var points: number[][] = [];
if (!encodedLine) {
return points;
}
var index = 0;
var xsum = 0;
var ysum = 0;
while (index < encodedLine.length) {
var n = 0;
var k = 0;
debugger;
while (true) {
if (index >= encodedLine.length) {
return points;
}
var b = EncodingString.indexOf(encodedLine[index++]);
if (b == -1) {
return points;
}
n |= (b & 31) << k;
k += 5;
if (b < 32) {
break;
}
}
var diagonal = ((Math.sqrt(8 * n + 5) - 1) / 2);
n -= diagonal * (diagonal + 1) / 2;
var ny = n;
var nx = diagonal - ny;
nx = (nx >> 1) ^ -(nx & 1);
ny = (ny >> 1) ^ -(ny & 1);
xsum += nx;
ysum += ny;
points.push([ysum * 0.000001, xsum * 0.000001]);
}
console.log(points);
return points;
}
Expected input output:
Encoded string
qkoo7v4q-lmB0471BiuuNmo30B
Decoded points:
35.89431, -110.72522
35.89393, -110.72578
35.89374, -110.72606
35.89337, -110.72662
Bitwise operators treat their operands as a sequence of 32 bits
(zeroes and ones), rather than as decimal, hexadecimal, or octal
numbers. For example, the decimal number nine has a binary
representation of 1001. Bitwise operators perform their operations on
such binary representations, but they return standard JavaScript
numerical values.
(39 & 31) << 35 tries to shift 35 bits when there only 32
Bitwise Operators
To solve this problem you could use BigInt to perform those operations and then downcast it back to Number
Number((39n & 31n) << 35n)
You can try this:
function getPointsFromEncodedString(encodedLine) {
const EncodingString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
var points = [];
if (!encodedLine) {
return points;
}
var index = 0;
var xsum = 0;
var ysum = 0;
while (index < encodedLine.length) {
var n = 0n;
var k = 0n;
while (true) {
if (index >= encodedLine.length) {
return points;
}
var b = EncodingString.indexOf(encodedLine[index++]);
if (b === -1) {
return points;
}
n |= (b & 31n) << k;
k += 5n;
if (b < 32n) {
break;
}
}
var diagonal = ((Math.sqrt(8 * Number(n) + 5) - 1) / 2);
n -= diagonal * (diagonal + 1) / 2;
var ny = n;
var nx = diagonal - ny;
nx = (nx >> 1) ^ -(nx & 1);
ny = (ny >> 1) ^ -(ny & 1);
xsum += Number(nx);
ysum += Number(ny);
points.push([ysum * 0.000001, xsum * 0.000001]);
}
console.log(points);
return points;
}

Converting HashString from C to JS

I'm trying to convert this function from the Mozilla Firefox code base, it's called HashString. It calls a bunch of functions which are all in this file: https://dxr.mozilla.org/mozilla-central/source/mfbt/HashFunctions.h#294
So these are the C functions it calls:
static const uint32_t kGoldenRatioU32 = 0x9E3779B9U;
MOZ_WARN_UNUSED_RESULT inline uint32_t
HashString(const wchar_t* aStr)
{
return detail::HashUntilZero(aStr);
}
template<typename T>
uint32_t
HashUntilZero(const T* aStr)
{
uint32_t hash = 0;
for (T c; (c = *aStr); aStr++) {
hash = AddToHash(hash, c);
}
return hash;
}
MOZ_WARN_UNUSED_RESULT inline uint32_t
AddToHash(uint32_t aHash, A* aA)
{
/*
* You might think this function should just take a void*. But then we'd only
* catch data pointers and couldn't handle function pointers.
*/
static_assert(sizeof(aA) == sizeof(uintptr_t), "Strange pointer!");
return detail::AddUintptrToHash<sizeof(uintptr_t)>(aHash, uintptr_t(aA));
}
inline uint32_t
AddUintptrToHash<8>(uint32_t aHash, uintptr_t aValue)
{
/*
* The static cast to uint64_t below is necessary because this function
* sometimes gets compiled on 32-bit platforms (yes, even though it's a
* template and we never call this particular override in a 32-bit build). If
* we do aValue >> 32 on a 32-bit machine, we're shifting a 32-bit uintptr_t
* right 32 bits, and the compiler throws an error.
*/
uint32_t v1 = static_cast<uint32_t>(aValue);
uint32_t v2 = static_cast<uint32_t>(static_cast<uint64_t>(aValue) >> 32);
return AddU32ToHash(AddU32ToHash(aHash, v1), v2);
}
inline uint32_t
AddU32ToHash(uint32_t aHash, uint32_t aValue)
{
return kGoldenRatioU32 * (RotateBitsLeft32(aHash, 5) ^ aValue);
}
inline uint32_t
RotateBitsLeft32(uint32_t aValue, uint8_t aBits)
{
MOZ_ASSERT(aBits < 32);
return (aValue << aBits) | (aValue >> (32 - aBits));
}
And here is my js code:
function HashString(aStr, aLength) {
// moz win32 hash function
if (aLength) {
console.error('NS_ERROR_NOT_IMPLEMENTED');
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
} else {
return HashUntilZero(aStr);
}
}
function HashUntilZero(aStr) {
var hash = 0;
//for (T c; (c = *aStr); aStr++) {
for (var c=0; c<aStr.length; c++) {
hash = AddToHash(hash, aStr.charCodeAt(c));
}
return hash;
}
function AddToHash(aHash, aA) {
//return detail::AddU32ToHash(aHash, aA);
//return AddU32ToHash(aHash, aA);
//return detail::AddUintptrToHash<sizeof(uintptr_t)>(aHash, aA);
return AddUintptrToHash(aHash, aA);
}
function AddUintptrToHash(aHash, aValue) {
//return AddU32ToHash(aHash, static_cast<uint32_t>(aValue));
return AddU32ToHash(aHash, aValue);
}
function AddU32ToHash(aHash, aValue) {
var kGoldenRatioU32 = 0x9E3779B9;
return (kGoldenRatioU32 * (RotateBitsLeft32(aHash, 5) ^ aValue));
}
function RotateBitsLeft32(aValue, aBits) {
// MOZ_ASSERT(aBits < 32);
return (aValue << aBits) | (aValue >> (32 - aBits));
}
console.log(HashString('C:\Users\Vayeate\AppData\Roaming\Mozilla\Firefox\Profiles\aksozfjt.Unnamed Profile 10')); // should return 3181739213
This isn't working right, doing HashString('C:\Users\Vayeate\AppData\Roaming\Mozilla\Firefox\Profiles\aksozfjt.Unnamed Profile 10') should return to me 3181739213 however it's not. It keeps returning to me: -159266146140
Let's implement a more minimal C++ version first, which also dumps intermediate values which we can later compare.
#include <iostream>
#include <iomanip>
#include <stdint.h>
using namespace std;
static const uint32_t gr = 0x9E3779B9U;
template<typename T>
static uint32_t add(uint32_t hash, T val) {
const uint32_t rv = gr * (((hash << 5) | (hash >> 27)) ^ val);
cerr << dec << setw(7) << (uint32_t)val << " " << setw(14) << rv << " " << hex << rv << endl;
return rv;
}
int main() {
const auto text = string("C:\\Users\\Vayeate\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\aksozfjt.Unnamed Profile 10");
uint32_t rv = 0;
for (auto c: text) {
rv = add(rv, c);
}
cout << "Result: " << dec << setw(14) << rv << " " << hex << rv << endl;
}
Result: 3181739213 bda57ccd, so we're on the right track.
Now, for some Javascript:
GetNativePath returns an nsAutoCString aka. 8-bit string, by converting the internal 16-bit string to UTF-8.
Javascript does not actually know about 32-bit unsigned integers, just 32-bit signed integers, but there are some dirty tricks (mainly the >>> 0 "unsigned cast").
32-bit unsigned multiplication does not work, but we can actually implement that operation ourselves.
Properly escaping the backslashes \ in your test string also helps ;)
Putting these things together, I arrived at the following function, which seems to produce correct results.
/**
* Javascript implementation of
* https://hg.mozilla.org/mozilla-central/file/0cefb584fd1a/mfbt/HashFunctions.h
* aka. the mfbt hash function.
*/
let HashString = (function() {
// Note: >>>0 is basically a cast-to-unsigned for our purposes.
const encoder = new TextEncoder("utf-8");
const kGoldenRatio = 0x9E3779B9;
// Multiply two uint32_t like C++ would ;)
const mul32 = (a, b) => {
// Split into 16-bit integers (hi and lo words)
let ahi = (a >> 16) & 0xffff;
let alo = a & 0xffff;
let bhi = (b >> 16) & 0xffff
let blo = b & 0xffff;
// Compute new hi and lo seperately and recombine.
return (
(((((ahi * blo) + (alo * bhi)) & 0xffff) << 16) >>> 0) +
(alo * blo)
) >>> 0;
};
// kGoldenRatioU32 * (RotateBitsLeft32(aHash, 5) ^ aValue);
const add = (hash, val) => {
// Note, cannot >> 27 here, but / (1<<27) works as well.
let rotl5 = (
((hash << 5) >>> 0) |
(hash / (1<<27)) >>> 0
) >>> 0;
return mul32(kGoldenRatio, (rotl5 ^ val) >>> 0);
}
return function(text) {
// Convert to utf-8.
// Also decomposes the string into uint8_t values already.
let data = encoder.encode(text);
// Compute the actual hash
let rv = 0;
for (let c of data) {
rv = add(rv, c | 0);
}
return rv;
};
})();
let res = HashString('C:\\Users\\Vayeate\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\aksozfjt.Unnamed Profile 10');
console.log(res, res === 3181739213);
Might not be the most efficient implementation, but well, it works at least ;)
There is a simpler way
var file = new FileUtils.File('C:\\Users\\Vayeate\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\aksozfjt.Unnamed Profile 10');
file.QueryInterface(Ci.nsIHashable);
console.log(file.hashCode === 3181739213);

BIg number round up ending up in Ne+25 [duplicate]

JavaScript converts integers with more than 21 digits to scientific notation when used in a string context. I'm printing an integer as part of a URL. How can I prevent the conversion from happening?
There's Number.toFixed, but it uses scientific notation if the number is >= 1e21 and has a maximum precision of 20. Other than that, you can roll your own, but it will be messy.
function toFixed(x) {
if (Math.abs(x) < 1.0) {
var 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 {
var 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;
}
Above uses cheap-'n'-easy string repetition ((new Array(n+1)).join(str)). You could define String.prototype.repeat using Russian Peasant Multiplication and use that instead.
This answer should only be applied to the context of the question: displaying a large number without using scientific notation. For anything else, you should use a BigInt library, such as BigNumber, Leemon's BigInt, or BigInteger. Going forward, the new native BigInt (note: not Leemon's) should be available; Chromium and browsers based on it (Chrome, the new Edge [v79+], Brave) and Firefox all have support; Safari's support is underway.
Here's how you'd use BigInt for it: BigInt(n).toString()
Example:
const n = 13523563246234613317632;
console.log("toFixed (wrong): " + n.toFixed());
console.log("BigInt (right): " + BigInt(n).toString());
Beware, though, that any integer you output as a JavaScript number (not a BigInt) that's more than 15-16 digits (specifically, greater than Number.MAX_SAFE_INTEGER + 1 [9,007,199,254,740,992]) may be be rounded, because JavaScript's number type (IEEE-754 double-precision floating point) can't precisely hold all integers beyond that point. As of Number.MAX_SAFE_INTEGER + 1 it's working in multiples of 2, so it can't hold odd numbers anymore (and similiarly, at 18,014,398,509,481,984 it starts working in multiples of 4, then 8, then 16, ...).
Consequently, if you can rely on BigInt support, output your number as a string you pass to the BigInt function:
const n = BigInt("YourNumberHere");
Example:
const n1 = BigInt(18014398509481985); // WRONG, will round to 18014398509481984
// before `BigInt` sees it
console.log(n1.toString() + " <== WRONG");
const n2 = BigInt("18014398509481985"); // RIGHT, BigInt handles it
console.log(n2.toString() + " <== Right");
I know this is an older question, but shows recently active. MDN toLocaleString
const myNumb = 1000000000000000000000;
console.log( myNumb ); // 1e+21
console.log( myNumb.toLocaleString() ); // "1,000,000,000,000,000,000,000"
console.log( myNumb.toLocaleString('fullwide', {useGrouping:false}) ); // "1000000000000000000000"
you can use options to format the output.
Note:
Number.toLocaleString() rounds after 16 decimal places, so that...
const myNumb = 586084736227728377283728272309128120398;
console.log( myNumb.toLocaleString('fullwide', { useGrouping: false }) );
...returns...
586084736227728400000000000000000000000
This is perhaps undesirable if accuracy is important in the intended result.
For small number, and you know how many decimals you want, you can use toFixed and then use a regexp to remove the trailing zeros.
Number(1e-7).toFixed(8).replace(/\.?0+$/,"") //0.000
Busting out the regular expressions. This has no precision issues and is not a lot of code.
function toPlainString(num) {
return (''+ +num).replace(/(-?)(\d*)\.?(\d*)e([+-]\d+)/,
function(a,b,c,d,e) {
return e < 0
? b + '0.' + Array(1-e-c.length).join(0) + c + d
: b + c + d + Array(e-d.length+1).join(0);
});
}
console.log(toPlainString(12345e+12));
console.log(toPlainString(12345e+24));
console.log(toPlainString(-12345e+24));
console.log(toPlainString(12345e-12));
console.log(toPlainString(123e-12));
console.log(toPlainString(-123e-12));
console.log(toPlainString(-123.45e-56));
console.log(toPlainString('1e-8'));
console.log(toPlainString('1.0e-8'));
The question of the post was avoiding e notation numbers and having the number as a plain number.
Therefore, if all is needed is to convert e (scientific) notation numbers to plain numbers (including in the case of fractional numbers) without loss of accuracy, then it is essential to avoid the use of the Math object and other javascript number methods so that rounding does not occur when large numbers and large fractions are handled (which always happens due to the internal storage in binary format).
The following function converts e (scientific) notation numbers to plain numbers (including fractions) handling both large numbers and large fractions without loss of accuracy as it does not use the built-in math and number functions to handle or manipulate the number.
The function also handles normal numbers, so that a number that is suspected to become in an 'e' notation can be passed to the function for fixing.
The function should work with different locale decimal points.
94 test cases are provided.
For large e-notation numbers pass the number as a string.
Examples:
eToNumber("123456789123456789.111122223333444455556666777788889999e+50");
// output:
"12345678912345678911112222333344445555666677778888999900000000000000"
eToNumber("123.456123456789123456895e-80");
// output:
"0.00000000000000000000000000000000000000000000000000000000000000000000000000000123456123456789123456895"
eToNumber("123456789123456789.111122223333444455556666777788889999e-50");
// output:
"0.00000000000000000000000000000000123456789123456789111122223333444455556666777788889999"
Valid e-notation numbers in Javascript include the following:
123e1 ==> 1230
123E1 ==> 1230
123e+1 ==> 1230
123.e+1 ==> 1230
123e-1 ==> 12.3
0.1e-1 ==> 0.01
.1e-1 ==> 0.01
-123e1 ==> -1230
/******************************************************************
* Converts e-Notation Numbers to Plain Numbers
******************************************************************
* #function eToNumber(number)
* #version 1.00
* #param {e nottation Number} valid Number in exponent format.
* pass number as a string for very large 'e' numbers or with large fractions
* (none 'e' number returned as is).
* #return {string} a decimal number string.
* #author Mohsen Alyafei
* #date 17 Jan 2020
* Note: No check is made for NaN or undefined input numbers.
*
*****************************************************************/
function eToNumber(num) {
let sign = "";
(num += "").charAt(0) == "-" && (num = num.substring(1), sign = "-");
let arr = num.split(/[e]/ig);
if (arr.length < 2) return sign + num;
let dot = (.1).toLocaleString().substr(1, 1), n = arr[0], exp = +arr[1],
w = (n = n.replace(/^0+/, '')).replace(dot, ''),
pos = n.split(dot)[1] ? n.indexOf(dot) + exp : w.length + exp,
L = pos - w.length, s = "" + BigInt(w);
w = exp >= 0 ? (L >= 0 ? s + "0".repeat(L) : r()) : (pos <= 0 ? "0" + dot + "0".repeat(Math.abs(pos)) + s : r());
L= w.split(dot); if (L[0]==0 && L[1]==0 || (+w==0 && +s==0) ) w = 0; //** added 9/10/2021
return sign + w;
function r() {return w.replace(new RegExp(`^(.{${pos}})(.)`), `$1${dot}$2`)}
}
//*****************************************************************
//================================================
// Test Cases
//================================================
let r = 0; // test tracker
r |= test(1, "123456789123456789.111122223333444455556666777788889999e+50", "12345678912345678911112222333344445555666677778888999900000000000000");
r |= test(2, "123456789123456789.111122223333444455556666777788889999e-50", "0.00000000000000000000000000000000123456789123456789111122223333444455556666777788889999");
r |= test(3, "123456789e3", "123456789000");
r |= test(4, "123456789e1", "1234567890");
r |= test(5, "1.123e3", "1123");
r |= test(6, "12.123e3", "12123");
r |= test(7, "1.1234e1", "11.234");
r |= test(8, "1.1234e4", "11234");
r |= test(9, "1.1234e5", "112340");
r |= test(10, "123e+0", "123");
r |= test(11, "123E0", "123");
// //============================
r |= test(12, "123e-1", "12.3");
r |= test(13, "123e-2", "1.23");
r |= test(14, "123e-3", "0.123");
r |= test(15, "123e-4", "0.0123");
r |= test(16, "123e-2", "1.23");
r |= test(17, "12345.678e-1", "1234.5678");
r |= test(18, "12345.678e-5", "0.12345678");
r |= test(19, "12345.678e-6", "0.012345678");
r |= test(20, "123.4e-2", "1.234");
r |= test(21, "123.4e-3", "0.1234");
r |= test(22, "123.4e-4", "0.01234");
r |= test(23, "-123e+0", "-123");
r |= test(24, "123e1", "1230");
r |= test(25, "123e3", "123000");
r |= test(26, -1e33, "-1000000000000000000000000000000000");
r |= test(27, "123e+3", "123000");
r |= test(28, "123E+7", "1230000000");
r |= test(29, "-123.456e+1", "-1234.56");
r |= test(30, "-1.0e+1", "-10");
r |= test(31, "-1.e+1", "-10");
r |= test(32, "-1e+1", "-10");
r |= test(34, "-0", "-0");
r |= test(37, "0e0", "0");
r |= test(38, "123.456e+4", "1234560");
r |= test(39, "123E-0", "123");
r |= test(40, "123.456e+50", "12345600000000000000000000000000000000000000000000000");
r |= test(41, "123e-0", "123");
r |= test(42, "123e-1", "12.3");
r |= test(43, "123e-3", "0.123");
r |= test(44, "123.456E-1", "12.3456");
r |= test(45, "123.456123456789123456895e-80", "0.00000000000000000000000000000000000000000000000000000000000000000000000000000123456123456789123456895");
r |= test(46, "-123.456e-50", "-0.00000000000000000000000000000000000000000000000123456");
r |= test(47, "-0e+1", "-0");
r |= test(48, "0e+1", "0");
r |= test(49, "0.1e+1", "1");
r |= test(50, "-0.01e+1", "-0.1");
r |= test(51, "0.01e+1", "0.1");
r |= test(52, "-123e-7", "-0.0000123");
r |= test(53, "123.456e-4", "0.0123456");
r |= test(54, "1.e-5", "0.00001"); // handle missing base fractional part
r |= test(55, ".123e3", "123"); // handle missing base whole part
// The Electron's Mass:
r |= test(56, "9.10938356e-31", "0.000000000000000000000000000000910938356");
// The Earth's Mass:
r |= test(57, "5.9724e+24", "5972400000000000000000000");
// Planck constant:
r |= test(58, "6.62607015e-34", "0.000000000000000000000000000000000662607015");
r |= test(59, "0.000e3", "0");
r |= test(60, "0.000000000000000e3", "0");
r |= test(61, "-0.0001e+9", "-100000");
r |= test(62, "-0.0e1", "-0");
r |= test(63, "-0.0000e1", "-0");
r |= test(64, "1.2000e0", "1.2000");
r |= test(65, "1.2000e-0", "1.2000");
r |= test(66, "1.2000e+0", "1.2000");
r |= test(67, "1.2000e+10", "12000000000");
r |= test(68, "1.12356789445566771234e2", "112.356789445566771234");
// ------------- testing for Non e-Notation Numbers -------------
r |= test(69, "12345.7898", "12345.7898") // no exponent
r |= test(70, 12345.7898, "12345.7898") // no exponent
r |= test(71, 0.00000000000001, "0.00000000000001") // from 1e-14
r |= test(72, 0.0000000000001, "0.0000000000001") // from 1e-13
r |= test(73, 0.000000000001, "0.000000000001") // from 1e-12
r |= test(74, 0.00000000001, "0.00000000001") // from 1e-11
r |= test(75, 0.0000000001, "0.0000000001") // from 1e-10
r |= test(76, 0.000000001, "0.000000001") // from 1e-9
r |= test(77, 0.00000001, "0.00000001") // from 1e-8
r |= test(78, 0.0000001, "0.0000001") // from 1e-7
r |= test(79, 1e-7, "0.0000001") // from 1e-7
r |= test(80, -0.0000001, "-0.0000001") // from 1e-7
r |= test(81, 0.0000005, "0.0000005") // from 1e-7
r |= test(82, 0.1000005, "0.1000005") // from 1e-7
r |= test(83, 1e-6, "0.000001") // from 1e-6
r |= test(84, 0.000001, "0.000001"); // from 1e-6
r |= test(85, 0.00001, "0.00001"); // from 1e-5
r |= test(86, 0.0001, "0.0001"); // from 1e-4
r |= test(87, 0.001, "0.001"); // from 1e-3
r |= test(88, 0.01, "0.01"); // from 1e-2
r |= test(89, 0.1, "0.1") // from 1e-1
r |= test(90, -0.0000000000000345, "-0.0000000000000345"); // from -3.45e-14
r |= test(91, -0, "0");
r |= test(92, "-0", "-0");
r |= test(93,2e64,"20000000000000000000000000000000000000000000000000000000000000000");
r |= test(94,"2830869077153280552556547081187254342445169156730","2830869077153280552556547081187254342445169156730");
if (r == 0) console.log("All 94 tests passed.");
//================================================
// Test function
//================================================
function test(testNumber, n1, should) {
let result = eToNumber(n1);
if (result !== should) {
console.log(`Test ${testNumber} Failed. Output: ${result}\n Should be: ${should}`);
return 1;
}
}
one more possible solution:
function toFix(i){
var str='';
do{
let a = i%10;
i=Math.trunc(i/10);
str = a+str;
}while(i>0)
return str;
}
Here is my short variant of Number.prototype.toFixed method that works with any number:
Number.prototype.toFixedSpecial = function(n) {
var str = this.toFixed(n);
if (str.indexOf('e+') === -1)
return str;
// if number is in scientific notation, pick (b)ase and (p)ower
str = str.replace('.', '').split('e+').reduce(function(b, p) {
return b + Array(p - b.length + 2).join(0);
});
if (n > 0)
str += '.' + Array(n + 1).join(0);
return str;
};
console.log( 1e21.toFixedSpecial(2) ); // "1000000000000000000000.00"
console.log( 2.1e24.toFixedSpecial(0) ); // "2100000000000000000000000"
console.log( 1234567..toFixedSpecial(1) ); // "1234567.0"
console.log( 1234567.89.toFixedSpecial(3) ); // "1234567.890"
The following solution bypasses the automatic exponentional formatting for very big and very small numbers. This is outis's solution with a bugfix: It was not working for very small negative numbers.
function numberToString(num)
{
let numStr = String(num);
if (Math.abs(num) < 1.0)
{
let e = parseInt(num.toString().split('e-')[1]);
if (e)
{
let negative = num < 0;
if (negative) num *= -1
num *= Math.pow(10, e - 1);
numStr = '0.' + (new Array(e)).join('0') + num.toString().substring(2);
if (negative) numStr = "-" + numStr;
}
}
else
{
let e = parseInt(num.toString().split('+')[1]);
if (e > 20)
{
e -= 20;
num /= Math.pow(10, e);
numStr = num.toString() + (new Array(e + 1)).join('0');
}
}
return numStr;
}
// testing ...
console.log(numberToString(+0.0000000000000000001));
console.log(numberToString(-0.0000000000000000001));
console.log(numberToString(+314564649798762418795));
console.log(numberToString(-314564649798762418795));
The answers of others do not give you the exact number!
This function calculates the desired number accurately and returns it in the string to prevent it from being changed by javascript!
If you need a numerical result, just multiply the result of the function in number one!
function toNonExponential(value) {
// if value is not a number try to convert it to number
if (typeof value !== "number") {
value = parseFloat(value);
// after convert, if value is not a number return empty string
if (isNaN(value)) {
return "";
}
}
var sign;
var e;
// if value is negative, save "-" in sign variable and calculate the absolute value
if (value < 0) {
sign = "-";
value = Math.abs(value);
}
else {
sign = "";
}
// if value is between 0 and 1
if (value < 1.0) {
// get e value
e = parseInt(value.toString().split('e-')[1]);
// if value is exponential convert it to non exponential
if (e) {
value *= Math.pow(10, e - 1);
value = '0.' + (new Array(e)).join('0') + value.toString().substring(2);
}
}
else {
// get e value
e = parseInt(value.toString().split('e+')[1]);
// if value is exponential convert it to non exponential
if (e) {
value /= Math.pow(10, e);
value += (new Array(e + 1)).join('0');
}
}
// if value has negative sign, add to it
return sign + value;
}
You can use from-exponential module. It is lightweight and fully tested.
import fromExponential from 'from-exponential';
fromExponential(1.123e-10); // => '0.0000000001123'
Your question:
number :0x68656c6c6f206f72656f
display:4.9299704811152646e+23
You can use this: https://github.com/MikeMcl/bignumber.js
A JavaScript library for arbitrary-precision decimal and non-decimal arithmetic.
like this:
let ten =new BigNumber('0x68656c6c6f206f72656f',16);
console.log(ten.toString(10));
display:492997048111526447310191
Use .toPrecision, .toFixed, etc. You can count the number of digits in your number by converting it to a string with .toString then looking at its .length.
You can loop over the number and achieve the rounding
// functionality to replace char at given index
String.prototype.replaceAt=function(index, character) {
return this.substr(0, index) + character + this.substr(index+character.length);
}
// looping over the number starts
var str = "123456789123456799.55";
var arr = str.split('.');
str = arr[0];
i = (str.length-1);
if(arr[1].length && Math.round(arr[1]/100)){
while(i>0){
var intVal = parseInt(str.charAt(i));
if(intVal == 9){
str = str.replaceAt(i,'0');
console.log(1,str)
}else{
str = str.replaceAt(i,(intVal+1).toString());
console.log(2,i,(intVal+1).toString(),str)
break;
}
i--;
}
}
This is what I ended up using to take the value from an input, expanding numbers less than 17digits and converting Exponential numbers to x10y
// e.g.
// niceNumber("1.24e+4") becomes
// 1.24x10 to the power of 4 [displayed in Superscript]
function niceNumber(num) {
try{
var sOut = num.toString();
if ( sOut.length >=17 || sOut.indexOf("e") > 0){
sOut=parseFloat(num).toPrecision(5)+"";
sOut = sOut.replace("e","x10<sup>")+"</sup>";
}
return sOut;
}
catch ( e) {
return num;
}
}
I think there may be several similar answers, but here's a thing I came up with
// If you're gonna tell me not to use 'with' I understand, just,
// it has no other purpose, ;( andthe code actually looks neater
// 'with' it but I will edit the answer if anyone insists
var commas = false;
function digit(number1, index1, base1) {
with (Math) {
return floor(number1/pow(base1, index1))%base1;
}
}
function digits(number1, base1) {
with (Math) {
o = "";
l = floor(log10(number1)/log10(base1));
for (var index1 = 0; index1 < l+1; index1++) {
o = digit(number1, index1, base1) + o;
if (commas && i%3==2 && i<l) {
o = "," + o;
}
}
return o;
}
}
// Test - this is the limit of accurate digits I think
console.log(1234567890123450);
Note: this is only as accurate as the javascript math functions and has problems when using log instead of log10 on the line before the for loop; it will write 1000 in base-10 as 000 so I changed it to log10 because people will mostly be using base-10 anyways.
This may not be a very accurate solution but I'm proud to say it can successfully translate numbers across bases and comes with an option for commas!
This didn't help me:
console.log( myNumb.toLocaleString('fullwide', {useGrouping:false}) );
but this:
value.toLocaleString("fullwide", {
useGrouping: false,
maximumSignificantDigits: 20,
})
Try this:
Number.standardizenumber = function (number,n) {
var mantissa = number.toLocaleString(
'en-US', {
useGrouping: false,
signDisplay: "never",
notation: "scientific",
minimumFractionDigits: 16,
maximumFractionDigits: 16
}
).toLowerCase().split('e')[0].replace(/\./g,'');
var exponentNegative = "0".repeat(Math.max(+Math.abs(number).toExponential().toLowerCase().split('e-')[1]-1,0)) + mantissa;
var exponentPositive = Math.abs(number)<1E17?mantissa.slice(0,+Math.abs(number).toExponential().toLowerCase().split('e+')[1]+1):mantissa+(Math.abs(number).toExponential().toLowerCase().split('e+')[1]-16);
var decimalExpPositive = Math.abs(number)<1E17?mantissa.slice(0,Math.abs(number).toExponential().toLowerCase().split('e+')[0]-16):undefined;
var fullDec = number===0?(1/number<0?'-0':'0'):(1/Math.sign(number)<0?'-':'')+(Math.abs(number)>=1?[exponentPositive,(number%1===0?(decimalExpPositive.slice(+Math.abs(number).toExponential().toLowerCase().split('e+')[1]+1)): undefined)].join('.'):`.${exponentNegative}`);
return isNaN(number)===false&&Math.abs(number)<1E17?((number%1===0?number.toLocaleString('en-US', {useGrouping: false}):fullDec).includes('.')===false?fullDec.split('.')[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","):fullDec.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1').replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",")):number.toLocaleString('en-US');
}
Number.standardizenumber(.0000001) // .0000001
Number.standardizenumber(1E21) // 1,000,000,000,000,000,000,000
Number.standardizenumber(1_234_567_890.123456) // 1,234,567,890.123456
I know it's many years later, but I had been working on a similar issue recently and I wanted to post my solution. The currently accepted answer pads out the exponent part with 0's, and mine attempts to find the exact answer, although in general it isn't perfectly accurate for very large numbers because of JS's limit in floating point precision.
This does work for Math.pow(2, 100), returning the correct value of 1267650600228229401496703205376.
function toFixed(x) {
var result = '';
var xStr = x.toString(10);
var digitCount = xStr.indexOf('e') === -1 ? xStr.length : (parseInt(xStr.substr(xStr.indexOf('e') + 1)) + 1);
for (var i = 1; i <= digitCount; i++) {
var mod = (x % Math.pow(10, i)).toString(10);
var exponent = (mod.indexOf('e') === -1) ? 0 : parseInt(mod.substr(mod.indexOf('e')+1));
if ((exponent === 0 && mod.length !== i) || (exponent > 0 && exponent !== i-1)) {
result = '0' + result;
}
else {
result = mod.charAt(0) + result;
}
}
return result;
}
console.log(toFixed(Math.pow(2,100))); // 1267650600228229401496703205376
If you are just doing it for display, you can build an array from the digits before they're rounded.
var num = Math.pow(2, 100);
var reconstruct = [];
while(num > 0) {
reconstruct.unshift(num % 10);
num = Math.floor(num / 10);
}
console.log(reconstruct.join(''));
I tried working with the string form rather than the number and this seemed to work. I have only tested this on Chrome but it should be universal:
function removeExponent(s) {
var ie = s.indexOf('e');
if (ie != -1) {
if (s.charAt(ie + 1) == '-') {
// negative exponent, prepend with .0s
var n = s.substr(ie + 2).match(/[0-9]+/);
s = s.substr(2, ie - 2); // remove the leading '0.' and exponent chars
for (var i = 0; i < n; i++) {
s = '0' + s;
}
s = '.' + s;
} else {
// positive exponent, postpend with 0s
var n = s.substr(ie + 1).match(/[0-9]+/);
s = s.substr(0, ie); // strip off exponent chars
for (var i = 0; i < n; i++) {
s += '0';
}
}
}
return s;
}
Currently there is no native function to dissolve scientific notation. However, for this purpose you must write your own functionality.
Here is my:
function dissolveExponentialNotation(number)
{
if(!Number.isFinite(number)) { return undefined; }
let text = number.toString();
let items = text.split('e');
if(items.length == 1) { return text; }
let significandText = items[0];
let exponent = parseInt(items[1]);
let characters = Array.from(significandText);
let minus = characters[0] == '-';
if(minus) { characters.splice(0, 1); }
let indexDot = characters.reduce((accumulator, character, index) =>
{
if(!accumulator.found) { if(character == '.') { accumulator.found = true; } else { accumulator.index++; } }
return accumulator;
}, { index: 0, found: false }).index;
characters.splice(indexDot, 1);
indexDot += exponent;
if(indexDot >= 0 && indexDot < characters.length - 1)
{
characters.splice(indexDot, 0, '.');
}
else if(indexDot < 0)
{
characters.unshift("0.", "0".repeat(-indexDot));
}
else
{
characters.push("0".repeat(indexDot - characters.length));
}
return (minus ? "-" : "") + characters.join("");
}
If you don't mind using Lodash, it has toSafeInteger()
_.toSafeInteger(3.2);
// => 3
_.toSafeInteger(Number.MIN_VALUE);
// => 0
_.toSafeInteger(Infinity);
// => 9007199254740991
_.toSafeInteger('3.2');
// => 3
You can also use YourJS.fullNumber. For instance YourJS.fullNumber(Number.MAX_VALUE) results in the following:
179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
It also works for really small numbers. YourJS.fullNumber(Number.MIN_VALUE) returns this:
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005
It is important to note that this function will always return finite numbers as strings but will return non-finite numbers (eg. NaN or Infinity) as undefined.
You can test it out in the YourJS Console here.
function printInt(n) { return n.toPrecision(100).replace(/\..*/,""); }
with some issues:
0.9 is displayed as "0"
-0.9 is displayed as "-0"
1e100 is displayed as "1"
works only for numbers up to ~1e99 => use other constant for greater numbers; or smaller for optimization.
You can use number.toString(10.1):
console.log(Number.MAX_VALUE.toString(10.1));
Note: This currently works in Chrome, but not in Firefox. The specification says the radix has to be an integer, so this results in unreliable behavior.
If you want to convert scientific notation to integer :
parseInt("5.645656456454545e+23", 10)
result: 5
I had the same issue with oracle returning scientic notation, but I needed the actual number for a url. I just used a PHP trick by subtracting zero, and I get the correct number.
for example 5.4987E7 is the val.
newval = val - 0;
newval now equals 54987000

How to avoid scientific notation for large numbers in JavaScript?

JavaScript converts integers with more than 21 digits to scientific notation when used in a string context. I'm printing an integer as part of a URL. How can I prevent the conversion from happening?
There's Number.toFixed, but it uses scientific notation if the number is >= 1e21 and has a maximum precision of 20. Other than that, you can roll your own, but it will be messy.
function toFixed(x) {
if (Math.abs(x) < 1.0) {
var 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 {
var 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;
}
Above uses cheap-'n'-easy string repetition ((new Array(n+1)).join(str)). You could define String.prototype.repeat using Russian Peasant Multiplication and use that instead.
This answer should only be applied to the context of the question: displaying a large number without using scientific notation. For anything else, you should use a BigInt library, such as BigNumber, Leemon's BigInt, or BigInteger. Going forward, the new native BigInt (note: not Leemon's) should be available; Chromium and browsers based on it (Chrome, the new Edge [v79+], Brave) and Firefox all have support; Safari's support is underway.
Here's how you'd use BigInt for it: BigInt(n).toString()
Example:
const n = 13523563246234613317632;
console.log("toFixed (wrong): " + n.toFixed());
console.log("BigInt (right): " + BigInt(n).toString());
Beware, though, that any integer you output as a JavaScript number (not a BigInt) that's more than 15-16 digits (specifically, greater than Number.MAX_SAFE_INTEGER + 1 [9,007,199,254,740,992]) may be be rounded, because JavaScript's number type (IEEE-754 double-precision floating point) can't precisely hold all integers beyond that point. As of Number.MAX_SAFE_INTEGER + 1 it's working in multiples of 2, so it can't hold odd numbers anymore (and similiarly, at 18,014,398,509,481,984 it starts working in multiples of 4, then 8, then 16, ...).
Consequently, if you can rely on BigInt support, output your number as a string you pass to the BigInt function:
const n = BigInt("YourNumberHere");
Example:
const n1 = BigInt(18014398509481985); // WRONG, will round to 18014398509481984
// before `BigInt` sees it
console.log(n1.toString() + " <== WRONG");
const n2 = BigInt("18014398509481985"); // RIGHT, BigInt handles it
console.log(n2.toString() + " <== Right");
I know this is an older question, but shows recently active. MDN toLocaleString
const myNumb = 1000000000000000000000;
console.log( myNumb ); // 1e+21
console.log( myNumb.toLocaleString() ); // "1,000,000,000,000,000,000,000"
console.log( myNumb.toLocaleString('fullwide', {useGrouping:false}) ); // "1000000000000000000000"
you can use options to format the output.
Note:
Number.toLocaleString() rounds after 16 decimal places, so that...
const myNumb = 586084736227728377283728272309128120398;
console.log( myNumb.toLocaleString('fullwide', { useGrouping: false }) );
...returns...
586084736227728400000000000000000000000
This is perhaps undesirable if accuracy is important in the intended result.
For small number, and you know how many decimals you want, you can use toFixed and then use a regexp to remove the trailing zeros.
Number(1e-7).toFixed(8).replace(/\.?0+$/,"") //0.000
Busting out the regular expressions. This has no precision issues and is not a lot of code.
function toPlainString(num) {
return (''+ +num).replace(/(-?)(\d*)\.?(\d*)e([+-]\d+)/,
function(a,b,c,d,e) {
return e < 0
? b + '0.' + Array(1-e-c.length).join(0) + c + d
: b + c + d + Array(e-d.length+1).join(0);
});
}
console.log(toPlainString(12345e+12));
console.log(toPlainString(12345e+24));
console.log(toPlainString(-12345e+24));
console.log(toPlainString(12345e-12));
console.log(toPlainString(123e-12));
console.log(toPlainString(-123e-12));
console.log(toPlainString(-123.45e-56));
console.log(toPlainString('1e-8'));
console.log(toPlainString('1.0e-8'));
The question of the post was avoiding e notation numbers and having the number as a plain number.
Therefore, if all is needed is to convert e (scientific) notation numbers to plain numbers (including in the case of fractional numbers) without loss of accuracy, then it is essential to avoid the use of the Math object and other javascript number methods so that rounding does not occur when large numbers and large fractions are handled (which always happens due to the internal storage in binary format).
The following function converts e (scientific) notation numbers to plain numbers (including fractions) handling both large numbers and large fractions without loss of accuracy as it does not use the built-in math and number functions to handle or manipulate the number.
The function also handles normal numbers, so that a number that is suspected to become in an 'e' notation can be passed to the function for fixing.
The function should work with different locale decimal points.
94 test cases are provided.
For large e-notation numbers pass the number as a string.
Examples:
eToNumber("123456789123456789.111122223333444455556666777788889999e+50");
// output:
"12345678912345678911112222333344445555666677778888999900000000000000"
eToNumber("123.456123456789123456895e-80");
// output:
"0.00000000000000000000000000000000000000000000000000000000000000000000000000000123456123456789123456895"
eToNumber("123456789123456789.111122223333444455556666777788889999e-50");
// output:
"0.00000000000000000000000000000000123456789123456789111122223333444455556666777788889999"
Valid e-notation numbers in Javascript include the following:
123e1 ==> 1230
123E1 ==> 1230
123e+1 ==> 1230
123.e+1 ==> 1230
123e-1 ==> 12.3
0.1e-1 ==> 0.01
.1e-1 ==> 0.01
-123e1 ==> -1230
/******************************************************************
* Converts e-Notation Numbers to Plain Numbers
******************************************************************
* #function eToNumber(number)
* #version 1.00
* #param {e nottation Number} valid Number in exponent format.
* pass number as a string for very large 'e' numbers or with large fractions
* (none 'e' number returned as is).
* #return {string} a decimal number string.
* #author Mohsen Alyafei
* #date 17 Jan 2020
* Note: No check is made for NaN or undefined input numbers.
*
*****************************************************************/
function eToNumber(num) {
let sign = "";
(num += "").charAt(0) == "-" && (num = num.substring(1), sign = "-");
let arr = num.split(/[e]/ig);
if (arr.length < 2) return sign + num;
let dot = (.1).toLocaleString().substr(1, 1), n = arr[0], exp = +arr[1],
w = (n = n.replace(/^0+/, '')).replace(dot, ''),
pos = n.split(dot)[1] ? n.indexOf(dot) + exp : w.length + exp,
L = pos - w.length, s = "" + BigInt(w);
w = exp >= 0 ? (L >= 0 ? s + "0".repeat(L) : r()) : (pos <= 0 ? "0" + dot + "0".repeat(Math.abs(pos)) + s : r());
L= w.split(dot); if (L[0]==0 && L[1]==0 || (+w==0 && +s==0) ) w = 0; //** added 9/10/2021
return sign + w;
function r() {return w.replace(new RegExp(`^(.{${pos}})(.)`), `$1${dot}$2`)}
}
//*****************************************************************
//================================================
// Test Cases
//================================================
let r = 0; // test tracker
r |= test(1, "123456789123456789.111122223333444455556666777788889999e+50", "12345678912345678911112222333344445555666677778888999900000000000000");
r |= test(2, "123456789123456789.111122223333444455556666777788889999e-50", "0.00000000000000000000000000000000123456789123456789111122223333444455556666777788889999");
r |= test(3, "123456789e3", "123456789000");
r |= test(4, "123456789e1", "1234567890");
r |= test(5, "1.123e3", "1123");
r |= test(6, "12.123e3", "12123");
r |= test(7, "1.1234e1", "11.234");
r |= test(8, "1.1234e4", "11234");
r |= test(9, "1.1234e5", "112340");
r |= test(10, "123e+0", "123");
r |= test(11, "123E0", "123");
// //============================
r |= test(12, "123e-1", "12.3");
r |= test(13, "123e-2", "1.23");
r |= test(14, "123e-3", "0.123");
r |= test(15, "123e-4", "0.0123");
r |= test(16, "123e-2", "1.23");
r |= test(17, "12345.678e-1", "1234.5678");
r |= test(18, "12345.678e-5", "0.12345678");
r |= test(19, "12345.678e-6", "0.012345678");
r |= test(20, "123.4e-2", "1.234");
r |= test(21, "123.4e-3", "0.1234");
r |= test(22, "123.4e-4", "0.01234");
r |= test(23, "-123e+0", "-123");
r |= test(24, "123e1", "1230");
r |= test(25, "123e3", "123000");
r |= test(26, -1e33, "-1000000000000000000000000000000000");
r |= test(27, "123e+3", "123000");
r |= test(28, "123E+7", "1230000000");
r |= test(29, "-123.456e+1", "-1234.56");
r |= test(30, "-1.0e+1", "-10");
r |= test(31, "-1.e+1", "-10");
r |= test(32, "-1e+1", "-10");
r |= test(34, "-0", "-0");
r |= test(37, "0e0", "0");
r |= test(38, "123.456e+4", "1234560");
r |= test(39, "123E-0", "123");
r |= test(40, "123.456e+50", "12345600000000000000000000000000000000000000000000000");
r |= test(41, "123e-0", "123");
r |= test(42, "123e-1", "12.3");
r |= test(43, "123e-3", "0.123");
r |= test(44, "123.456E-1", "12.3456");
r |= test(45, "123.456123456789123456895e-80", "0.00000000000000000000000000000000000000000000000000000000000000000000000000000123456123456789123456895");
r |= test(46, "-123.456e-50", "-0.00000000000000000000000000000000000000000000000123456");
r |= test(47, "-0e+1", "-0");
r |= test(48, "0e+1", "0");
r |= test(49, "0.1e+1", "1");
r |= test(50, "-0.01e+1", "-0.1");
r |= test(51, "0.01e+1", "0.1");
r |= test(52, "-123e-7", "-0.0000123");
r |= test(53, "123.456e-4", "0.0123456");
r |= test(54, "1.e-5", "0.00001"); // handle missing base fractional part
r |= test(55, ".123e3", "123"); // handle missing base whole part
// The Electron's Mass:
r |= test(56, "9.10938356e-31", "0.000000000000000000000000000000910938356");
// The Earth's Mass:
r |= test(57, "5.9724e+24", "5972400000000000000000000");
// Planck constant:
r |= test(58, "6.62607015e-34", "0.000000000000000000000000000000000662607015");
r |= test(59, "0.000e3", "0");
r |= test(60, "0.000000000000000e3", "0");
r |= test(61, "-0.0001e+9", "-100000");
r |= test(62, "-0.0e1", "-0");
r |= test(63, "-0.0000e1", "-0");
r |= test(64, "1.2000e0", "1.2000");
r |= test(65, "1.2000e-0", "1.2000");
r |= test(66, "1.2000e+0", "1.2000");
r |= test(67, "1.2000e+10", "12000000000");
r |= test(68, "1.12356789445566771234e2", "112.356789445566771234");
// ------------- testing for Non e-Notation Numbers -------------
r |= test(69, "12345.7898", "12345.7898") // no exponent
r |= test(70, 12345.7898, "12345.7898") // no exponent
r |= test(71, 0.00000000000001, "0.00000000000001") // from 1e-14
r |= test(72, 0.0000000000001, "0.0000000000001") // from 1e-13
r |= test(73, 0.000000000001, "0.000000000001") // from 1e-12
r |= test(74, 0.00000000001, "0.00000000001") // from 1e-11
r |= test(75, 0.0000000001, "0.0000000001") // from 1e-10
r |= test(76, 0.000000001, "0.000000001") // from 1e-9
r |= test(77, 0.00000001, "0.00000001") // from 1e-8
r |= test(78, 0.0000001, "0.0000001") // from 1e-7
r |= test(79, 1e-7, "0.0000001") // from 1e-7
r |= test(80, -0.0000001, "-0.0000001") // from 1e-7
r |= test(81, 0.0000005, "0.0000005") // from 1e-7
r |= test(82, 0.1000005, "0.1000005") // from 1e-7
r |= test(83, 1e-6, "0.000001") // from 1e-6
r |= test(84, 0.000001, "0.000001"); // from 1e-6
r |= test(85, 0.00001, "0.00001"); // from 1e-5
r |= test(86, 0.0001, "0.0001"); // from 1e-4
r |= test(87, 0.001, "0.001"); // from 1e-3
r |= test(88, 0.01, "0.01"); // from 1e-2
r |= test(89, 0.1, "0.1") // from 1e-1
r |= test(90, -0.0000000000000345, "-0.0000000000000345"); // from -3.45e-14
r |= test(91, -0, "0");
r |= test(92, "-0", "-0");
r |= test(93,2e64,"20000000000000000000000000000000000000000000000000000000000000000");
r |= test(94,"2830869077153280552556547081187254342445169156730","2830869077153280552556547081187254342445169156730");
if (r == 0) console.log("All 94 tests passed.");
//================================================
// Test function
//================================================
function test(testNumber, n1, should) {
let result = eToNumber(n1);
if (result !== should) {
console.log(`Test ${testNumber} Failed. Output: ${result}\n Should be: ${should}`);
return 1;
}
}
one more possible solution:
function toFix(i){
var str='';
do{
let a = i%10;
i=Math.trunc(i/10);
str = a+str;
}while(i>0)
return str;
}
Here is my short variant of Number.prototype.toFixed method that works with any number:
Number.prototype.toFixedSpecial = function(n) {
var str = this.toFixed(n);
if (str.indexOf('e+') === -1)
return str;
// if number is in scientific notation, pick (b)ase and (p)ower
str = str.replace('.', '').split('e+').reduce(function(b, p) {
return b + Array(p - b.length + 2).join(0);
});
if (n > 0)
str += '.' + Array(n + 1).join(0);
return str;
};
console.log( 1e21.toFixedSpecial(2) ); // "1000000000000000000000.00"
console.log( 2.1e24.toFixedSpecial(0) ); // "2100000000000000000000000"
console.log( 1234567..toFixedSpecial(1) ); // "1234567.0"
console.log( 1234567.89.toFixedSpecial(3) ); // "1234567.890"
The following solution bypasses the automatic exponentional formatting for very big and very small numbers. This is outis's solution with a bugfix: It was not working for very small negative numbers.
function numberToString(num)
{
let numStr = String(num);
if (Math.abs(num) < 1.0)
{
let e = parseInt(num.toString().split('e-')[1]);
if (e)
{
let negative = num < 0;
if (negative) num *= -1
num *= Math.pow(10, e - 1);
numStr = '0.' + (new Array(e)).join('0') + num.toString().substring(2);
if (negative) numStr = "-" + numStr;
}
}
else
{
let e = parseInt(num.toString().split('+')[1]);
if (e > 20)
{
e -= 20;
num /= Math.pow(10, e);
numStr = num.toString() + (new Array(e + 1)).join('0');
}
}
return numStr;
}
// testing ...
console.log(numberToString(+0.0000000000000000001));
console.log(numberToString(-0.0000000000000000001));
console.log(numberToString(+314564649798762418795));
console.log(numberToString(-314564649798762418795));
The answers of others do not give you the exact number!
This function calculates the desired number accurately and returns it in the string to prevent it from being changed by javascript!
If you need a numerical result, just multiply the result of the function in number one!
function toNonExponential(value) {
// if value is not a number try to convert it to number
if (typeof value !== "number") {
value = parseFloat(value);
// after convert, if value is not a number return empty string
if (isNaN(value)) {
return "";
}
}
var sign;
var e;
// if value is negative, save "-" in sign variable and calculate the absolute value
if (value < 0) {
sign = "-";
value = Math.abs(value);
}
else {
sign = "";
}
// if value is between 0 and 1
if (value < 1.0) {
// get e value
e = parseInt(value.toString().split('e-')[1]);
// if value is exponential convert it to non exponential
if (e) {
value *= Math.pow(10, e - 1);
value = '0.' + (new Array(e)).join('0') + value.toString().substring(2);
}
}
else {
// get e value
e = parseInt(value.toString().split('e+')[1]);
// if value is exponential convert it to non exponential
if (e) {
value /= Math.pow(10, e);
value += (new Array(e + 1)).join('0');
}
}
// if value has negative sign, add to it
return sign + value;
}
You can use from-exponential module. It is lightweight and fully tested.
import fromExponential from 'from-exponential';
fromExponential(1.123e-10); // => '0.0000000001123'
Your question:
number :0x68656c6c6f206f72656f
display:4.9299704811152646e+23
You can use this: https://github.com/MikeMcl/bignumber.js
A JavaScript library for arbitrary-precision decimal and non-decimal arithmetic.
like this:
let ten =new BigNumber('0x68656c6c6f206f72656f',16);
console.log(ten.toString(10));
display:492997048111526447310191
Use .toPrecision, .toFixed, etc. You can count the number of digits in your number by converting it to a string with .toString then looking at its .length.
You can loop over the number and achieve the rounding
// functionality to replace char at given index
String.prototype.replaceAt=function(index, character) {
return this.substr(0, index) + character + this.substr(index+character.length);
}
// looping over the number starts
var str = "123456789123456799.55";
var arr = str.split('.');
str = arr[0];
i = (str.length-1);
if(arr[1].length && Math.round(arr[1]/100)){
while(i>0){
var intVal = parseInt(str.charAt(i));
if(intVal == 9){
str = str.replaceAt(i,'0');
console.log(1,str)
}else{
str = str.replaceAt(i,(intVal+1).toString());
console.log(2,i,(intVal+1).toString(),str)
break;
}
i--;
}
}
This is what I ended up using to take the value from an input, expanding numbers less than 17digits and converting Exponential numbers to x10y
// e.g.
// niceNumber("1.24e+4") becomes
// 1.24x10 to the power of 4 [displayed in Superscript]
function niceNumber(num) {
try{
var sOut = num.toString();
if ( sOut.length >=17 || sOut.indexOf("e") > 0){
sOut=parseFloat(num).toPrecision(5)+"";
sOut = sOut.replace("e","x10<sup>")+"</sup>";
}
return sOut;
}
catch ( e) {
return num;
}
}
I think there may be several similar answers, but here's a thing I came up with
// If you're gonna tell me not to use 'with' I understand, just,
// it has no other purpose, ;( andthe code actually looks neater
// 'with' it but I will edit the answer if anyone insists
var commas = false;
function digit(number1, index1, base1) {
with (Math) {
return floor(number1/pow(base1, index1))%base1;
}
}
function digits(number1, base1) {
with (Math) {
o = "";
l = floor(log10(number1)/log10(base1));
for (var index1 = 0; index1 < l+1; index1++) {
o = digit(number1, index1, base1) + o;
if (commas && i%3==2 && i<l) {
o = "," + o;
}
}
return o;
}
}
// Test - this is the limit of accurate digits I think
console.log(1234567890123450);
Note: this is only as accurate as the javascript math functions and has problems when using log instead of log10 on the line before the for loop; it will write 1000 in base-10 as 000 so I changed it to log10 because people will mostly be using base-10 anyways.
This may not be a very accurate solution but I'm proud to say it can successfully translate numbers across bases and comes with an option for commas!
This didn't help me:
console.log( myNumb.toLocaleString('fullwide', {useGrouping:false}) );
but this:
value.toLocaleString("fullwide", {
useGrouping: false,
maximumSignificantDigits: 20,
})
Try this:
Number.standardizenumber = function (number,n) {
var mantissa = number.toLocaleString(
'en-US', {
useGrouping: false,
signDisplay: "never",
notation: "scientific",
minimumFractionDigits: 16,
maximumFractionDigits: 16
}
).toLowerCase().split('e')[0].replace(/\./g,'');
var exponentNegative = "0".repeat(Math.max(+Math.abs(number).toExponential().toLowerCase().split('e-')[1]-1,0)) + mantissa;
var exponentPositive = Math.abs(number)<1E17?mantissa.slice(0,+Math.abs(number).toExponential().toLowerCase().split('e+')[1]+1):mantissa+(Math.abs(number).toExponential().toLowerCase().split('e+')[1]-16);
var decimalExpPositive = Math.abs(number)<1E17?mantissa.slice(0,Math.abs(number).toExponential().toLowerCase().split('e+')[0]-16):undefined;
var fullDec = number===0?(1/number<0?'-0':'0'):(1/Math.sign(number)<0?'-':'')+(Math.abs(number)>=1?[exponentPositive,(number%1===0?(decimalExpPositive.slice(+Math.abs(number).toExponential().toLowerCase().split('e+')[1]+1)): undefined)].join('.'):`.${exponentNegative}`);
return isNaN(number)===false&&Math.abs(number)<1E17?((number%1===0?number.toLocaleString('en-US', {useGrouping: false}):fullDec).includes('.')===false?fullDec.split('.')[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","):fullDec.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1').replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, ",")):number.toLocaleString('en-US');
}
Number.standardizenumber(.0000001) // .0000001
Number.standardizenumber(1E21) // 1,000,000,000,000,000,000,000
Number.standardizenumber(1_234_567_890.123456) // 1,234,567,890.123456
I know it's many years later, but I had been working on a similar issue recently and I wanted to post my solution. The currently accepted answer pads out the exponent part with 0's, and mine attempts to find the exact answer, although in general it isn't perfectly accurate for very large numbers because of JS's limit in floating point precision.
This does work for Math.pow(2, 100), returning the correct value of 1267650600228229401496703205376.
function toFixed(x) {
var result = '';
var xStr = x.toString(10);
var digitCount = xStr.indexOf('e') === -1 ? xStr.length : (parseInt(xStr.substr(xStr.indexOf('e') + 1)) + 1);
for (var i = 1; i <= digitCount; i++) {
var mod = (x % Math.pow(10, i)).toString(10);
var exponent = (mod.indexOf('e') === -1) ? 0 : parseInt(mod.substr(mod.indexOf('e')+1));
if ((exponent === 0 && mod.length !== i) || (exponent > 0 && exponent !== i-1)) {
result = '0' + result;
}
else {
result = mod.charAt(0) + result;
}
}
return result;
}
console.log(toFixed(Math.pow(2,100))); // 1267650600228229401496703205376
If you are just doing it for display, you can build an array from the digits before they're rounded.
var num = Math.pow(2, 100);
var reconstruct = [];
while(num > 0) {
reconstruct.unshift(num % 10);
num = Math.floor(num / 10);
}
console.log(reconstruct.join(''));
I tried working with the string form rather than the number and this seemed to work. I have only tested this on Chrome but it should be universal:
function removeExponent(s) {
var ie = s.indexOf('e');
if (ie != -1) {
if (s.charAt(ie + 1) == '-') {
// negative exponent, prepend with .0s
var n = s.substr(ie + 2).match(/[0-9]+/);
s = s.substr(2, ie - 2); // remove the leading '0.' and exponent chars
for (var i = 0; i < n; i++) {
s = '0' + s;
}
s = '.' + s;
} else {
// positive exponent, postpend with 0s
var n = s.substr(ie + 1).match(/[0-9]+/);
s = s.substr(0, ie); // strip off exponent chars
for (var i = 0; i < n; i++) {
s += '0';
}
}
}
return s;
}
Currently there is no native function to dissolve scientific notation. However, for this purpose you must write your own functionality.
Here is my:
function dissolveExponentialNotation(number)
{
if(!Number.isFinite(number)) { return undefined; }
let text = number.toString();
let items = text.split('e');
if(items.length == 1) { return text; }
let significandText = items[0];
let exponent = parseInt(items[1]);
let characters = Array.from(significandText);
let minus = characters[0] == '-';
if(minus) { characters.splice(0, 1); }
let indexDot = characters.reduce((accumulator, character, index) =>
{
if(!accumulator.found) { if(character == '.') { accumulator.found = true; } else { accumulator.index++; } }
return accumulator;
}, { index: 0, found: false }).index;
characters.splice(indexDot, 1);
indexDot += exponent;
if(indexDot >= 0 && indexDot < characters.length - 1)
{
characters.splice(indexDot, 0, '.');
}
else if(indexDot < 0)
{
characters.unshift("0.", "0".repeat(-indexDot));
}
else
{
characters.push("0".repeat(indexDot - characters.length));
}
return (minus ? "-" : "") + characters.join("");
}
If you don't mind using Lodash, it has toSafeInteger()
_.toSafeInteger(3.2);
// => 3
_.toSafeInteger(Number.MIN_VALUE);
// => 0
_.toSafeInteger(Infinity);
// => 9007199254740991
_.toSafeInteger('3.2');
// => 3
You can also use YourJS.fullNumber. For instance YourJS.fullNumber(Number.MAX_VALUE) results in the following:
179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
It also works for really small numbers. YourJS.fullNumber(Number.MIN_VALUE) returns this:
0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005
It is important to note that this function will always return finite numbers as strings but will return non-finite numbers (eg. NaN or Infinity) as undefined.
You can test it out in the YourJS Console here.
function printInt(n) { return n.toPrecision(100).replace(/\..*/,""); }
with some issues:
0.9 is displayed as "0"
-0.9 is displayed as "-0"
1e100 is displayed as "1"
works only for numbers up to ~1e99 => use other constant for greater numbers; or smaller for optimization.
You can use number.toString(10.1):
console.log(Number.MAX_VALUE.toString(10.1));
Note: This currently works in Chrome, but not in Firefox. The specification says the radix has to be an integer, so this results in unreliable behavior.
If you want to convert scientific notation to integer :
parseInt("5.645656456454545e+23", 10)
result: 5
I had the same issue with oracle returning scientic notation, but I needed the actual number for a url. I just used a PHP trick by subtracting zero, and I get the correct number.
for example 5.4987E7 is the val.
newval = val - 0;
newval now equals 54987000

Categories

Resources