Próbuję skrócić liczby dziesiętne do miejsc dziesiętnych. Coś takiego:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2)
robi właściwie, ale zaokrągla wartość. Nie potrzebuję zaokrąglenia wartości. Mam nadzieję, że jest to możliwe w javascript.
Próbuję skrócić liczby dziesiętne do miejsc dziesiętnych. Coś takiego:
5.467 -> 5.46
985.943 -> 985.94
toFixed(2)
robi właściwie, ale zaokrągla wartość. Nie potrzebuję zaokrąglenia wartości. Mam nadzieję, że jest to możliwe w javascript.
Odpowiedzi:
upd :
Okazało się, że zaokrąglanie błędów zawsze będzie cię prześladować, bez względu na to, jak bardzo będziesz próbował je zrekompensować. Dlatego problem należy rozwiązać, przedstawiając liczby dokładnie w notacji dziesiętnej.
Number.prototype.toFixedDown = function(digits) { var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"), m = this.toString().match(re); return m ? parseFloat(m[1]) : this.valueOf(); }; [ 5.467.toFixedDown(2), 985.943.toFixedDown(2), 17.56.toFixedDown(2), (0).toFixedDown(1), 1.11.toFixedDown(1) + 22]; // [5.46, 985.94, 17.56, 0, 23.1]
Stare, podatne na błędy rozwiązanie oparte na kompilacji innych:
Number.prototype.toFixedDown = function(digits) { var n = this - Math.pow(10, -digits)/2; n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56" return n.toFixed(digits); }
źródło
1.11.toFixedDown(1) + 22
kończy się jako1.122
zamiast23.1
.0.toFixedDown(1)
Powinien także produkować,0
ale zamiast tego produkuje-0.1
.(-10.2131).toFixedDown(2) // ==> 10.21
. : .(1e-7).toFixedDown(0) // ==> 1e-7
. Robi to za1e-(>=7)
(ex:1e-8
,1e-9
, ...).Odpowiedź Dogberta jest dobra, ale jeśli twój kod może mieć do czynienia z liczbami ujemnymi,
Math.floor
sam w sobie może dać nieoczekiwane wyniki.Np.
Math.floor(4.3) = 4
AleMath.floor(-4.3) = -5
Zamiast tego użyj funkcji pomocniczej, takiej jak ta, aby uzyskać spójne wyniki:
truncateDecimals = function (number) { return Math[number < 0 ? 'ceil' : 'floor'](number); }; // Applied to Dogbert's answer: var a = 5.467; var truncated = truncateDecimals(a * 100) / 100; // = 5.46
Oto wygodniejsza wersja tej funkcji:
truncateDecimals = function (number, digits) { var multiplier = Math.pow(10, digits), adjustedNum = number * multiplier, truncatedNum = Math[adjustedNum < 0 ? 'ceil' : 'floor'](adjustedNum); return truncatedNum / multiplier; }; // Usage: var a = 5.467; var truncated = truncateDecimals(a, 2); // = 5.46 // Negative digits: var b = 4235.24; var truncated = truncateDecimals(b, -2); // = 4200
Jeśli to nie jest pożądane zachowanie, wstaw wywołanie do
Math.abs
w pierwszej linii:var multiplier = Math.pow(10, Math.abs(digits)),
EDYCJA: shendz poprawnie wskazuje, że użycie tego rozwiązania w
a = 17.56
przypadku nieprawidłowego wyprodukowania17.55
. Aby dowiedzieć się więcej o tym, dlaczego tak się dzieje, przeczytaj artykuł Co każdy informatyk powinien wiedzieć o arytmetyce zmiennoprzecinkowej . Niestety, napisanie rozwiązania, które eliminuje wszystkie źródła błędów zmiennoprzecinkowych, jest dość trudne w przypadku javascript. W innym języku użyłbyś liczb całkowitych lub może typu dziesiętnego, ale z javascript ...To rozwiązanie powinno być w 100% dokładne, ale będzie też wolniejsze:
function truncateDecimals (num, digits) { var numS = num.toString(), decPos = numS.indexOf('.'), substrLength = decPos == -1 ? numS.length : 1 + decPos + digits, trimmedResult = numS.substr(0, substrLength), finalResult = isNaN(trimmedResult) ? 0 : trimmedResult; return parseFloat(finalResult); }
Dla tych, którzy potrzebują szybkości, ale chcą również uniknąć błędów zmiennoprzecinkowych, spróbuj czegoś takiego jak BigDecimal.js . Inne biblioteki javascript BigDecimal można znaleźć w tym pytaniu SO: „Czy istnieje dobra biblioteka BigDecimal Javascript?” a oto dobry wpis na blogu o bibliotekach matematycznych dla JavaScript
źródło
if(isNAN(result) result = 0;
Zależy od żądanego zachowania.var a = 5.467; var truncated = Math.floor(a * 100) / 100; // = 5.46
źródło
truncate(-3.14)
i otrzymam-4
odpowiedź, zdecydowanie nazwałbym to niepożądanym.var a = 65.1
var truncated = Math.floor(a * 100) / 100; // = 65.09
Dlatego nie jest to właściwe rozwiązanieMożesz naprawić zaokrąglenie, odejmując 0,5 dla toFixed, np
(f - 0.005).toFixed(2)
źródło
Rozważyć wykorzystanie podwójnego tyldy:
~~
.Weź pod uwagę liczbę. Pomnóż przez cyfry znaczące po przecinku, aby skrócić do zera miejsc za pomocą
~~
. Podzielić ten mnożnik z powrotem. Zysk.function truncator(numToTruncate, intDecimalPlaces) { var numPower = Math.pow(10, intDecimalPlaces); // "numPowerConverter" might be better return ~~(numToTruncate * numPower)/numPower; }
Próbuję oprzeć się zawinięciu
~~
rozmowy w pareny; Uważam, że kolejność operacji powinna sprawić, że będzie to działać poprawnie.alert(truncator(5.1231231, 1)); // is 5.1
alert(truncator(-5.73, 1)); // is -5.7
alert(truncator(-5.73, 0)); // is -5
Link do JSFiddle .
EDYCJA: Patrząc wstecz, nieumyślnie zająłem się również sprawami, aby zaokrąglić lewą część dziesiętną.
alert(truncator(4343.123, -2)); // gives 4300.
Logika jest trochę zwariowana, szukając tego zastosowania i może skorzystać na szybkim refaktorze. Ale nadal działa. Lepsze szczęście niż dobre.
źródło
Math
prototyp o to i sprawdzisz NaN-y przed wykonaniem, byłoby to po prostu idealne.truncator((10 * 2.9) / 100, 2)
return 0.28 zamiast 0.29 ... jsfiddle.net/25tgrzq1Ładne rozwiązanie jednowierszowe:
function truncate (num, places) { return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places); }
Następnie zadzwoń za pomocą:
truncate(3.5636232, 2); // returns 3.56 truncate(5.4332312, 3); // returns 5.433 truncate(25.463214, 4); // returns 25.4632
źródło
Pomyślałem, że dorzucę odpowiedź za pomocą,
|
ponieważ jest prosta i działa dobrze.truncate = function(number, places) { var shift = Math.pow(10, places); return ((number * shift) | 0) / shift; };
źródło
or
z 0 oznacza „po prostu zachowaj to, co już mam”. Robi to, co moja~~
odpowiedź, ale za pomocą jednej operacji bitowej. Chociaż ma to samo ograniczenie, co napisano: nie możemy przekroczyć 2 ^ 31 .truncate((10 * 2.9) / 100);
ten kod zwraca 0,28 zamiast 0,29 jsfiddle.net/9pf0732dObetnij za pomocą operatorów bitowych:
~~0.5 === 0 ~~(-0.5) === 0 ~~14.32794823 === 14 ~~(-439.93) === -439
źródło
Odpowiedź @ Dogberta można poprawić za pomocą
Math.trunc
, która obcina zamiast zaokrąglać.var a = 5.467; var truncated = Math.trunc(a * 100) / 100; // = 5.46
var a = -5.467; var truncated = Math.trunc(a * 100) / 100; // = -5.46
źródło
Math.trunc
, ale raczej niż9.28 * 100
jest927.9999
raczej niż928
. Możesz przeczytać The Perils of Floating PointNapisałem odpowiedź krótszą metodą. Oto co wymyśliłem
function truncate(value, precision) { var step = Math.pow(10, precision || 0); var temp = Math.trunc(step * value); return temp / step; }
Metoda może być używana w ten sposób
truncate(132456.25456789, 5)); // Output: 132456.25456 truncate(132456.25456789, 3)); // Output: 132456.254 truncate(132456.25456789, 1)); // Output: 132456.2 truncate(132456.25456789)); // Output: 132456
Lub, jeśli chcesz mieć krótszą składnię, proszę bardzo
function truncate(v, p) { var s = Math.pow(10, p || 0); return Math.trunc(s * v) / s; }
źródło
Number.prototype.trim = function(decimals) { var s = this.toString(); var d = s.split("."); d[1] = d[1].substring(0, decimals); return parseFloat(d.join(".")); } console.log((5.676).trim(2)); //logs 5.67
źródło
Myślę, że ta funkcja mogłaby być prostym rozwiązaniem:
function trunc(decimal,n=2){ let x = decimal + ''; // string return x.lastIndexOf('.')>=0?parseFloat(x.substr(0,x.lastIndexOf('.')+(n+1))):decimal; // You can use indexOf() instead of lastIndexOf() } console.log(trunc(-241.31234,2)); console.log(trunc(241.312,5)); console.log(trunc(-241.233)); console.log(trunc(241.2,0)); console.log(trunc(241));
źródło
Znalazłem problem: rozważając następną sytuację: 2.1 lub 1.2 lub -6.4
Co jeśli chcesz zawsze mieć 3 miejsca po przecinku lub dwa lub gdziekolwiek, więc musisz uzupełnić początkowe zera po prawej stronie
// 3 decimals numbers 0.5 => 0.500 // 6 decimals 0.1 => 0.10000 // 4 decimales -2.1 => -2.1000 // truncate to 3 decimals 3.11568 => 3.115
To stała funkcja Nicka Knowlsona
function truncateDecimals (num, digits) { var numS = num.toString(); var decPos = numS.indexOf('.'); var substrLength = decPos == -1 ? numS.length : 1 + decPos + digits; var trimmedResult = numS.substr(0, substrLength); var finalResult = isNaN(trimmedResult) ? 0 : trimmedResult; // adds leading zeros to the right if (decPos != -1){ var s = trimmedResult+""; decPos = s.indexOf('.'); var decLength = s.length - decPos; while (decLength <= digits){ s = s + "0"; decPos = s.indexOf('.'); decLength = s.length - decPos; substrLength = decPos == -1 ? s.length : 1 + decPos + digits; }; finalResult = s; } return finalResult; };
https://jsfiddle.net/huttn155/7/
źródło
x = 0.0000
testtruncateDecimals (x, 2)
kończy się niepowodzeniem. zwraca0
. nie tak jak oczekiwano0.00
function toFixed(number, digits) { var reg_ex = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)") var array = number.toString().match(reg_ex); return array ? parseFloat(array[1]) : number.valueOf() } var test = 10.123456789 var __fixed = toFixed(test, 6) console.log(__fixed) // => 10.123456
źródło
Odpowiedź @kirilloid wydaje się być poprawną odpowiedzią, jednak główny kod wymaga aktualizacji. Jego rozwiązanie nie uwzględnia liczb ujemnych (o których ktoś wspomniał w sekcji komentarzy, ale nie zostało zaktualizowane w głównym kodzie).
Aktualizacja do kompletnego, ostatecznie przetestowanego rozwiązania:
Number.prototype.toFixedDown = function(digits) { var re = new RegExp("([-]*\\d+\\.\\d{" + digits + "})(\\d)"), m = this.toString().match(re); return m ? parseFloat(m[1]) : this.valueOf(); };
Przykładowe użycie:
var x = 3.1415629; Logger.log(x.toFixedDown(2)); //or use whatever you use to log
Fiddle: JS Number Zaokrąglij w dół
PS: Za mało repozytorium, aby skomentować to rozwiązanie.
źródło
Oto prosta, ale działająca funkcja obcinania liczby do 2 miejsc po przecinku.
function truncateNumber(num) { var num1 = ""; var num2 = ""; var num1 = num.split('.')[0]; num2 = num.split('.')[1]; var decimalNum = num2.substring(0, 2); var strNum = num1 +"."+ decimalNum; var finalNum = parseFloat(strNum); return finalNum; }
źródło
Wynikowy typ pozostaje liczbą ...
/* Return the truncation of n wrt base */ var trunc = function(n, base) { n = (n / base) | 0; return base * n; }; var t = trunc(5.467, 0.01);
źródło
Lodash posiada kilka metod narzędziowych matematyczne, które mogą okrągły , podłoga i ceil numer do danego dokładnością po przecinku. To pozostawia końcowe zera.
Przyjmują interesujące podejście, używając wykładnika liczby. Najwyraźniej pozwala to uniknąć zaokrąglania problemów.
(Uwaga:
func
jestMath.round
lubceil
lubfloor
w poniższym kodzie)// Shift with exponential notation to avoid floating-point issues. var pair = (toString(number) + 'e').split('e'), value = func(pair[0] + 'e' + (+pair[1] + precision)); pair = (toString(value) + 'e').split('e'); return +(pair[0] + 'e' + (+pair[1] - precision));
Link do kodu źródłowego
źródło
Oto moje podejście do tematu:
convert.truncate = function(value, decimals) { decimals = (decimals === undefined ? 0 : decimals); return parseFloat((value-(0.5/Math.pow(10, decimals))).toFixed(decimals),10); };
To tylko nieco bardziej rozbudowana wersja
(f - 0.005).toFixed(2)
źródło
Ten, który jest oznaczony jako rozwiązanie, jest lepszym rozwiązaniem, które znalazłem do dzisiaj, ale ma poważny problem z 0 (na przykład 0. toFixedDown (2) daje -0,01). Więc proponuję użyć tego:
Number.prototype.toFixedDown = function(digits) { if(this == 0) { return 0; } var n = this - Math.pow(10, -digits)/2; n += n / Math.pow(2, 53); // added 1360765523: 17.56.toFixedDown(2) === "17.56" return n.toFixed(digits); }
źródło
Oto czego używam:
var t = 1; for (var i = 0; i < decimalPrecision; i++) t = t * 10; var f = parseFloat(value); return (Math.floor(f * t)) / t;
źródło
const TO_FIXED_MAX = 100; function truncate(number, decimalsPrecison) { // make it a string with precision 1e-100 number = number.toFixed(TO_FIXED_MAX); // chop off uneccessary digits const dotIndex = number.indexOf('.'); number = number.substring(0, dotIndex + decimalsPrecison + 1); // back to a number data type (app specific) return Number.parseFloat(number); } // example truncate(0.00000001999, 8); 0.00000001
pracuje z:
źródło
tylko po to, aby wskazać proste rozwiązanie, które zadziałało dla mnie
przekonwertuj go na łańcuch, a następnie wykonaj regex ...
var number = 123.45678; var number_s = '' + number; var number_truncated_s = number_s.match(/\d*\.\d{4}/)[0] var number_truncated = parseFloat(number_truncated_s)
Można go skrócić do
var number_truncated = parseFloat(('' + 123.4568908).match(/\d*\.\d{4}/)[0])
źródło
Oto kod ES6, który robi to, co chcesz
const truncateTo = (unRouned, nrOfDecimals = 2) => { const parts = String(unRouned).split("."); if (parts.length !== 2) { // without any decimal part return unRouned; } const newDecimals = parts[1].slice(0, nrOfDecimals), newString = `${parts[0]}.${newDecimals}`; return Number(newString); }; // your examples console.log(truncateTo(5.467)); // ---> 5.46 console.log(truncateTo(985.943)); // ---> 985.94 // other examples console.log(truncateTo(5)); // ---> 5 console.log(truncateTo(-5)); // ---> -5 console.log(truncateTo(-985.943)); // ---> -985.94
źródło
Number.prototype.truncate = function(places) { var shift = Math.pow(10, places); return Math.trunc(this * shift) / shift; };
źródło
Możesz pracować ze sznurkami. Sprawdza, czy „.” istnieje, a następnie usuwa część ciągu.
obcięcie (7,88, 1) -> 7,8
obcięte (7,889, 2) -> 7,89
obcięcie (-7,88, 1) -> -7,88
function truncate(number, decimals) { const tmp = number + ''; if (tmp.indexOf('.') > -1) { return +tmp.substr(0 , tmp.indexOf('.') + decimals+1 ); } else { return +number } }
źródło
Jestem trochę zdezorientowany, dlaczego jest tak wiele różnych odpowiedzi na tak fundamentalnie proste pytanie; widziałem tylko dwa podejścia, które wydawały się warte uwagi. Zrobiłem szybki test porównawczy, aby zobaczyć różnicę prędkości za pomocą https://jsbench.me/ .
Oto rozwiązanie, które jest obecnie (26.09.2020) oflagowane jako odpowiedź:
function truncate(n, digits) { var re = new RegExp("(\\d+\\.\\d{" + digits + "})(\\d)"), m = n.toString().match(re); return m ? parseFloat(m[1]) : n.valueOf(); }; [ truncate(5.467,2), truncate(985.943,2), truncate(17.56,2), truncate(0, 1), truncate(1.11, 1) + 22];
Jednak jest to wykonywanie operacji na łańcuchach i wyrażeniach regularnych, co zwykle nie jest zbyt wydajne, a istnieje funkcja Math.trunc, która robi dokładnie to , czego chce OP, tylko bez miejsc po przecinku. Dlatego możesz łatwo użyć tego plus trochę dodatkowej arytmetyki, aby uzyskać to samo.
Oto kolejne rozwiązanie, które znalazłem w tym wątku, a którego użyłbym:
function truncate(n, digits) { var step = Math.pow(10, digits || 0); var temp = Math.trunc(step * n); return temp / step; } [ truncate(5.467,2), truncate(985.943,2), truncate(17.56,2), truncate(0, 1), truncate(1.11, 1) + 22];
Pierwsza metoda jest „o 99,92% wolniejsza” niż druga, więc druga jest zdecydowanie tą, którą polecam.
OK, wracając do szukania innych sposobów uniknięcia pracy ...
źródło