JavaScript wandelt Ganzzahlen mit mehr als 21 Ziffern in die wissenschaftliche Notation um, wenn sie in einem String-Kontext verwendet werden. Ich drucke eine Ganzzahl als Teil einer URL. Wie kann ich die Konvertierung verhindern?
Wie vermeide ich die wissenschaftliche Notation für große Zahlen in JavaScript?
Chris
außen
Es gibt Number.toFixaber es verwendet die wissenschaftliche Notation, wenn die Zahl >= 1e21 ist und eine maximale Genauigkeit von 20 hat. Ansonsten können Sie Ihre eigene würfeln, aber es wird chaotisch.
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;
}
Oben verwendet billige und einfache Saitenwiederholung ((new Array(n+1)).join(str)
). Du könntest definieren String.prototype.repeat
Verwenden Sie die russische Bauernmultiplikation und verwenden Sie diese stattdessen.
Diese Antwort sollte nur auf den Kontext der Frage angewendet werden: Anzeige einer großen Zahl ohne Verwendung der wissenschaftlichen Notation. Für alles andere sollten Sie eine BigInt-Bibliothek verwenden, z Große NummerLemons BigIntoder BigInteger. Vorwärts, der neue Eingeborene BigInt (Anmerkung: nicht von Lemon’s) sollte verfügbar sein; Chrom und darauf basierende Browser (Chromdas neue Rand [v79+], Tapfer) und Feuerfuchs alle haben Unterstützung; Die Unterstützung von Safari ist im Gange.
So verwenden Sie BigInt dafür: BigInt(n).toString()
Beispiel:
const n = 13523563246234613317632;
console.log("toFixed (wrong): " + n.toFixed());
console.log("BigInt (right): " + BigInt(n).toString());
In acht nehmendass jedoch jede Ganzzahl, die Sie als JavaScript-Zahl (kein BigInt) ausgeben, die mehr als 15-16 Ziffern hat (insbesondere größer als Number.MAX_SAFE_INTEGER + 1
[9,007,199,254,740,992]) kann gerundet werden, da der Zahlentyp von JavaScript (IEEE-754-Gleitkommazahl mit doppelter Genauigkeit) nicht alle Ganzzahlen über diesen Punkt hinaus genau aufnehmen kann. Ab Number.MAX_SAFE_INTEGER + 1
Es arbeitet in Vielfachen von 2, kann also keine ungeraden Zahlen mehr enthalten (und ähnlich beginnt es bei 18.014.398.509.481.984 in Vielfachen von 4, dann 8, dann 16, … zu arbeiten).
Folglich, wenn Sie sich darauf verlassen können BigInt
Support, geben Sie Ihre Nummer als Zeichenfolge aus, die Sie an die übergeben BigInt
Funktion:
const n = BigInt("YourNumberHere");
Beispiel:
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");
-
Ihre Lösung gibt mir ein ganz anderes Ergebnis für 2 ^ 1000 als Wolframalpha. Irgendwelche Hinweise?
– Shane Reustle
10. August 2011 um 22:50 Uhr
-
@Shane: In diesen Fragen und Antworten geht es darum, Gleitkommazahlen als Ganzzahlen zur Basis 10 anzuzeigen, und es werden keine Zahlen angesprochen, die nicht in einem Gleitkommaformat dargestellt werden können (was bei der Konvertierung in Basis 10 auftritt). Sie benötigen eine JS-Bigint-Bibliothek, wie in der letzten Zeile erwähnt.
– aussen
11. August 2011 um 1:05 Uhr
-
@PeterOlson: Sieht aus, als hätte ich a ausgelassen
Math.abs
. Danke für die Warnung.– aussen
23. März 2012 um 17:38 Uhr
-
toFixed(Number.MAX_VALUE) == Number.MAX_VALUE
sollte dann true zurückgeben, tut es aber nicht …– Mannthemat
17. Januar 2017 um 22:02 Uhr
-
Tatsächlich funktioniert dieser Code so wie er ist nicht für sehr kleine negative Zahlen: toFixed( -1E-20 ) -> “0.0000000000000000000.09999999999999999”
– Davidsachen
15. Juni 2017 um 0:37 Uhr
Pfannkuchen17
Ich weiß, dass dies eine ältere Frage ist, zeigt aber kürzlich aktiv. 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"
Sie können Optionen verwenden, um die Ausgabe zu formatieren.
Notiz:
Number.toLocaleString() rundet nach 16 Dezimalstellen, sodass …
const myNumb = 586084736227728377283728272309128120398;
console.log( myNumb.toLocaleString('fullwide', { useGrouping: false }) );
…kehrt zurück…
586084736227728400000000000000000000000
Dies ist möglicherweise unerwünscht, wenn die Genauigkeit für das beabsichtigte Ergebnis wichtig ist.
-
Dies ist die narrensichere Antwort.
– Arie
27. Oktober 2018 um 13:58 Uhr
-
Dies funktioniert in PhantomJS 2.1.1 nicht – es endet immer noch in der wissenschaftlichen Notation. Gut in Chrome.
– Egor Nepomnjaschih
1. März 2019 um 14:43 Uhr
-
Dies scheint bei sehr kleinen Dezimalstellen nicht zu funktionieren: var myNumb = 0.0000000001; console.log( myNumb.toLocaleString(‘fullwide’, { useGrouping: false }) );
– eh1160
26. August 2019 um 14:15 Uhr
-
Man kann die Option maximumSignificantDigits (max. 21) einstellen, um sehr kleine Dezimalzahlen zu formatieren, dh:
js console.log( myNumb.toLocaleString('fullwide', { useGrouping: true, maximumSignificantDigits:6}) );
– Herr. MaNiAl
26. November 2019 um 2:56 Uhr
-
Die Rundung nach 16 Stellen erfolgt nicht a
toLocaleString()
Einschränkung; es ist einNumber
Einschränkung.Number.MAX_SAFE_INTEGER = 9007199254740991
– forresthopkinsa
20. Juli 2021 um 4:45 Uhr
Für kleine Zahlen, und Sie wissen, wie viele Dezimalstellen Sie möchten, können Sie toFixed verwenden und dann einen regulären Ausdruck verwenden, um die nachgestellten Nullen zu entfernen.
Number(1e-7).toFixed(8).replace(/\.?0+$/,"") //0.000
-
Achten Sie darauf, 0 als Argument des toFixed-Aufrufs zu vermeiden – es führt dazu, dass signifikante nachgestellte Nullen gelöscht werden:
(1000).toFixed(0).replace(/\.?0+$/,"") // 1, not 1000
– Egor Nepomnjaschih
1. März 2019 um 14:33 Uhr
noch eine mögliche lösung:
function toFix(i){
var str="";
do{
let a = i%10;
i=Math.trunc(i/10);
str = a+str;
}while(i>0)
return str;
}
Vision
Hier ist meine kurze Variante von Number.prototype.toFixed
Methode, die mit jeder Zahl funktioniert:
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"
-
@manonthemat Natürlich sind sie nicht gleich, weil der erste formatiert ist Schnur und der zweite ist a
Number
. Wenn Sie den ersten zu a werfenNumber
Sie werden sehen, dass sie es sind absolut gleich: jsfiddle.net/qd6hpnyx/1. Sie können Ihre Ablehnung zurücknehmen:P
– Vision
18. Januar 2017 um 22:50 Uhr
-
fair genug … Mir ist gerade aufgefallen, dass ich das nicht kann, es sei denn, Sie bearbeiten Ihre Antwort.
– Mannthemat
18. Januar 2017 um 23:03 Uhr
-
Es ist besser, auch alle nachlaufenden zu ersetzen
.0
mit leerem String.– vsync
11. September 2018 um 7:14 Uhr
-
Ich erhalte einen etwas seltsamen Wert, wenn ich es versuche
console.log(2.2e307.toFixedSpecial(10))
. Ich meine… Ich bekomme mehrere nachgestellte Nullen. Ich stimme trotzdem hoch, weil dies dem, was ich brauche, am nächsten kommt.– peter.petrow
8. Oktober 2019 um 20:42 Uhr
-
@peter.petrov Ja, hast du
.0000000000
weil du angegeben hast10
als Parameter. Wenn Sie sie loswerden möchten, verwenden Sie0
.– Vision
9. Oktober 2019 um 9:40 Uhr
Erdomke
Zerschlagung der regulären Ausdrücke. Dies hat keine Genauigkeitsprobleme und ist nicht viel 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'));
-
@manonthemat Natürlich sind sie nicht gleich, weil der erste formatiert ist Schnur und der zweite ist a
Number
. Wenn Sie den ersten zu a werfenNumber
Sie werden sehen, dass sie es sind absolut gleich: jsfiddle.net/qd6hpnyx/1. Sie können Ihre Ablehnung zurücknehmen:P
– Vision
18. Januar 2017 um 22:50 Uhr
-
fair genug … Mir ist gerade aufgefallen, dass ich das nicht kann, es sei denn, Sie bearbeiten Ihre Antwort.
– Mannthemat
18. Januar 2017 um 23:03 Uhr
-
Es ist besser, auch alle nachlaufenden zu ersetzen
.0
mit leerem String.– vsync
11. September 2018 um 7:14 Uhr
-
Ich erhalte einen etwas seltsamen Wert, wenn ich es versuche
console.log(2.2e307.toFixedSpecial(10))
. Ich meine… Ich bekomme mehrere nachgestellte Nullen. Ich stimme trotzdem hoch, weil dies dem, was ich brauche, am nächsten kommt.– peter.petrow
8. Oktober 2019 um 20:42 Uhr
-
@peter.petrov Ja, hast du
.0000000000
weil du angegeben hast10
als Parameter. Wenn Sie sie loswerden möchten, verwenden Sie0
.– Vision
9. Oktober 2019 um 9:40 Uhr
Die Frage der Post bestand darin, E-Notationsnummern zu vermeiden und die Nummer als einfache Nummer zu haben.
Wenn also alles nötig ist, um e (wissenschaftliche) Notationszahlen in einfache Zahlen umzuwandeln (auch im Fall von Bruchzahlen) ohne Genauigkeitsverlust, dann ist es wichtig, die Verwendung von zu vermeiden Math
Objekt und Sonstiges Javascript-Zahlenmethoden damit beim Umgang mit großen Zahlen und großen Brüchen (was aufgrund der internen Speicherung im Binärformat immer passiert) keine Rundung auftritt.
Die folgende Funktion konvertiert e (wissenschaftliche) Notationszahlen in einfache Zahlen (einschließlich Brüche), wobei sowohl große Zahlen als auch große Brüche ohne Genauigkeitsverlust verarbeitet werden, da sie nicht die integrierten mathematischen und Zahlenfunktionen verwendet, um die Zahl zu verarbeiten oder zu manipulieren.
Die Funktion verarbeitet auch normale Zahlen, sodass eine Zahl, von der vermutet wird, dass sie zu einer ‘e’-Notation wird, zur Korrektur an die Funktion übergeben werden kann.
Die Funktion sollte mit unterschiedlichen Gebietsschema-Dezimalpunkten funktionieren.
Es werden 94 Testfälle bereitgestellt.
Bei großen Zahlen in E-Notation übergeben Sie die Zahl als Zeichenfolge.
Beispiele:
eToNumber("123456789123456789.111122223333444455556666777788889999e+50");
// output:
"12345678912345678911112222333344445555666677778888999900000000000000"
eToNumber("123.456123456789123456895e-80");
// output:
"0.00000000000000000000000000000000000000000000000000000000000000000000000000000123456123456789123456895"
eToNumber("123456789123456789.111122223333444455556666777788889999e-50");
// output:
"0.00000000000000000000000000000000123456789123456789111122223333444455556666777788889999"
Gültige E-Notationsnummern in Javascript sind:
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;
}
}
-
Sind wir sicher, dass das immer in jedem Land funktioniert? Ich bin ein bisschen besorgt über diese toLocaleString(), aber ich habe keine Möglichkeit, sie zu testen. Da dies wahrscheinlich niemand tut, müssen wir uns auf unser Verständnis dieser Funktion verlassen und sicherstellen, dass diese solide ist.
– FlorianB
24. September 2021 um 16:33 Uhr
-
@FlorianB Ich habe es mit DevTools noch einmal ausgiebig mit verschiedenen Locales getestet und funktioniert gut, wenn das Dezimaltrennzeichen ein Punkt “.” oder ein Komma “,”. Ich habe einen sehr seltsamen Fall gefunden, in dem die Zahl 0,00 ist, was 0,00 bedeutet, und ihn behoben.
– Mohsen Alyafei
8. Oktober 2021 um 23:14 Uhr
-
Sie haben bei diesem Code großartige Arbeit geleistet. Frage: Haben Sie auch ein Tool geschrieben, das in die entgegengesetzte Richtung konvertiert? Wenn ja, würde ich das auch gerne sehen.
– Lonnie Best
19. Oktober 2021 um 6:43 Uhr
-
@LonnieBest Ich denke, ich muss es verbessern und optimieren und das Gegenteil tun, wenn es die Zeit erlaubt. Danke
– Mohsen Alyafei
26. Oktober 2021 um 5:20 Uhr
Soll 1E21 als „1000000000000000000000“ angezeigt werden? Interessieren Sie sich dafür, wie die Nummer angezeigt oder gespeichert wird?
– aussen
6. November 2009 um 6:19 Uhr
Ich mache mir Sorgen darüber, wie es angezeigt wird: Ich habe einen document.write(myvariable)-Befehl
– Chris
6. November 2009 um 6:20 Uhr
Ich brauche die Nummer als Teil einer URL
– Chris
6. November 2009 um 21:43 Uhr
@outis: Menschliche Benutzer sind nicht die einzigen, die Zahlen lesen möchten. Es scheint, dass D3 eine Ausnahme auslöst, wenn es auf a trifft
translate
Transformation, die Koordinaten in wissenschaftlicher Schreibweise enthält.– OR-Mapper
7. September 2017 um 9:05 Uhr
Dies ist immer noch nützlich, wenn Sie mit Zahlen bis zu einer bestimmten Größe arbeiten. Die wissenschaftliche Notation wird für Benutzer, die die wissenschaftliche Notation nicht kennen, schwer lesbar sein.
– Hippiepfad
15. September 2017 um 3:08 Uhr