Obcinaj (nie zaokrąglaj) liczby dziesiętne 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 to, co właściwe, ale uzupełnia wartość. Nie potrzebuję zaokrąglania wartości. Mam nadzieję, że jest to możliwe w javascript.

Author: Rudi Visser, 2011-02-06

23 answers

Upd :

W końcu okazało się, że błędy zaokrąglania zawsze będą cię prześladować, bez względu na to, jak bardzo starasz się je zrekompensować. Dlatego problem powinien być atakowany przez reprezentowanie liczb 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 rozwiązanie podatne na błędy na podstawie 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);
}
 38
Author: kirilloid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-11 20:46:29

Odpowiedź Dogberta jest dobra, ale jeśli twój kod musi radzić sobie z liczbami ujemnymi, Math.floor sam w sobie może dać nieoczekiwane wyniki.

Np. Math.floor(4.3) = 4, ale Math.floor(-4.3) = -5

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 nie jest to pożądane zachowanie, Wstaw wywołanie Math.abs w pierwszej linii:

var multiplier = Math.pow(10, Math.abs(digits)),

EDIT: shendz użycie tego rozwiązania z {[8] } spowoduje niepoprawne wytworzenie 17.55. Aby dowiedzieć się więcej o tym, dlaczego tak się dzieje, przeczytaj co każdy informatyk powinien wiedzieć o arytmetyce zmiennoprzecinkowej . Niestety, pisanie rozwiązania, które eliminuje wszystkie źródła błędu zmiennoprzecinkowego, jest dość trudne w javascript. W innym języku można użyć liczb całkowitych lub może typu dziesiętnego, ale z javascript...

To rozwiązanie powinno być w 100% dokładne, ale będzie również wolniej:

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ą prędkości, ale również chcą uniknąć błędów zmiennoprzecinkowych, spróbuj czegoś takiego jak BigDecimal.js . Możesz znaleźć inne biblioteki javascript BigDecimal w tym tak pytanie: " czy istnieje dobra biblioteka Javascript BigDecimal?" A oto dobry wpis na blogu o bibliotekach matematycznych dla Javascript

 49
Author: Nick Knowlson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:39
var a = 5.467;
var truncated = Math.floor(a * 100) / 100; // = 5.46
 25
Author: Dogbert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-06 10:44:54

Można naprawić zaokrąglenie przez odjęcie 0,5 dla toFixed, np.

(f - 0.005).toFixed(2)
 20
Author: RichardTheKiwi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-06 10:47:14

Rozważ wykorzystanie podwójnej tyldy: ~~.

Weź numer. Pomnóż znaczącymi cyframi po przecinku, aby obcinać do zerowych miejsc za pomocą ~~. Podziel 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ę zawijaniu ~~ wywołania w parens; kolejność operacji powinna sprawić, że będzie działać poprawnie, jak sądzę.

alert(truncator(5.1231231, 1)); // is 5.1

alert(truncator(-5.73, 1)); // is -5.7

alert(truncator(-5.73, 0)); // is -5

JSFiddle link .

EDIT: patrząc wstecz, nieumyślnie zajmowałem się również sprawami, aby zaokrąglić lewy dziesiętny.

alert(truncator(4343.123, -2)); // gives 4300.

Logika jest trochę zwariowana patrząc na takie użycie i może skorzystać z szybkiego refaktoringu. Ale nadal działa. Lepiej mieć szczęście niż dobre.

 14
Author: ruffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:26

Pomyślałem, że dorzucę odpowiedź używając |, ponieważ jest prosta i działa dobrze.

truncate = function(number, places) {
  var shift = Math.pow(10, places);

  return ((number * shift) | 0) / shift;
};
 9
Author: Daniel X Moore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-18 00:15:04

Ładne rozwiązanie jednoliniowe:

function truncate (num, places) {
  return Math.trunc(num * Math.pow(10, places)) / Math.pow(10, places);
}

Następnie wywołaj przez:

truncate(3.5636232, 2); // returns 3.56
truncate(5.4332312, 3); // returns 5.433
truncate(25.463214, 4); // returns 25.4632
 8
Author: MeestorHok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-13 01:34:06

[[3]]@Dogbert odpowiedź można poprawić za pomocą Math.trunc, które obcinają zamiast zaokrąglać.

Istnieje różnica między zaokrągleniem a obcięciem. Obcinanie jest najwyraźniej zachowanie, którego szuka to pytanie. If I call obciąć (-3.14) i otrzymać -4 z powrotem, zdecydowanie nazwałbym to niepożądane. – @ NickKnowlson

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
 5
Author: zurfyx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-14 17:33:08

Obcinanie za pomocą operatorów bitowych:

~~0.5 === 0
~~(-0.5) === 0
~~14.32794823 === 14
~~(-439.93) === -439
 4
Author: John Strickler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-28 14:31:39

Ten, który jest oznaczony jako rozwiązanie, jest lepszym rozwiązaniem, które znalazłem do dziś, ale ma poważny problem z 0 (Na przykład 0.tofixeddown (2) daje -0.01). Proponuję więc 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);
}
 1
Author: Sebastián Rojas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-23 21:28:22

Tutaj jest prosta, ale działająca funkcja do 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;
            }
 1
Author: RohannG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-22 09:52:43
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
 1
Author: Max Zlotskiy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-23 19:23:47

Znalazłem problem: biorąc pod uwagę następną sytuację: 2.1 lub 1.2 lub -6.4

Co jeśli chcesz zawsze 3 dziesiętne, 2 lub wharever, więc musisz dopełnić wiodące zera w prawo

// 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

Jest 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/

 1
Author: juanpscotto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-26 21:21:34

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);
 1
Author: Bob Lyon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-25 22:13:00

Myślę, że ta funkcja może 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));
 1
Author: Julio Cesar Cervantes Martinez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-16 16:58:19

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)
 0
Author: opensas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-15 06:04:28

Żeby wskazać proste rozwiązanie, które zadziałało dla mnie

Przekonwertuje go na string, a następnie powtarza...

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])
 0
Author: Sergio Campamá,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-07 23:11:56

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;
 0
Author: Steve,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-17 11:47:59

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
 0
Author: Cristian Sima,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-30 17:19:54
Number.prototype.truncate = function(places) {
  var shift = Math.pow(10, places);

  return Math.trunc(this * shift) / shift;
};
 0
Author: Dercni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-03 05:55:07

Odpowiedź @ kirilloid wydaje się być poprawną odpowiedzią, jednak główny kod musi zostać zaktualizowany. Jego rozwiązanie nie zajmuje się liczbami ujemnymi (o których ktoś wspomniał w komentarzu, ale nie zostało zaktualizowane w kodzie głównym).

Aktualizacja tego do kompletnego, końcowego 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 Round down

PS: za mało repo, aby skomentować to rozwiązanie.

 0
Author: Jaiwardhan Terminal Swarnakar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-03 12:29:57
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
 0
Author: Flavio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-14 00:09:56

Lodash ma kilka matematycznych metod użytkowych, które mogą okrążyć, floor i ceil Liczba z określoną dokładnością dziesiętną. To pozostawia śladowe zera.

Przyjmują ciekawe podejście, używając wykładnika liczby. Najwyraźniej pozwala to uniknąć problemów z zaokrągleniem.

(Uwaga: func jest Math.round lub ceil lub floor w kodzie poniżej)

// 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

 0
Author: Matthias Dailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-26 04:47:26