Hoe rondt u af op maximaal 2 decimalen, indien nodig?

Ik wil maximaal 2 decimalen afronden, maar alleen indien nodig.

Invoer:

10
1.7777777
9.1

Uitvoer:

10
1.78
9.1

Hoe kan ik dit in JavaScript doen?


Antwoord 1, autoriteit 100%

Gebruik Math.round():

Math.round(num * 100) / 100

Of om specifieker te zijn en ervoor te zorgen dat zaken als 1.005 correct worden afgerond, gebruikt u Nummer.EPSILON :

Math.round((num + Number.EPSILON) * 100) / 100

Vergelijk het verschil.


Antwoord 2, autoriteit 82%

Als de waarde een teksttype is:

parseFloat("123.456").toFixed(2);

Als de waarde een getal is:

var numb = 123.23454;
numb = numb.toFixed(2);

Er is een nadeel dat waarden als 1,5 “1,50” als uitvoer opleveren. Een oplossing voorgesteld door @minitech:

var numb = 1.5;
numb = +numb.toFixed(2);
// Note the plus sign that drops any "extra" zeroes at the end.
// It changes the result (which is a string) into a number again (think "0 + foo"),
// which means that it uses only as many digits as necessary.

Het lijkt erop dat Math.roundeen betere oplossing is. Maar dat is het niet!In sommige gevallen zal het NIETcorrect afronden:

Math.round(1.005 * 1000)/1000 // Returns 1 instead of expected 1.01!

toFixed() zal in sommige gevallen ook NIETcorrect afronden (getest in Chrome v.55.0.2883.87)!

Voorbeelden:

parseFloat("1.555").toFixed(2); // Returns 1.55 instead of 1.56.
parseFloat("1.5550").toFixed(2); // Returns 1.55 instead of 1.56.
// However, it will return correct result if you round 1.5551.
parseFloat("1.5551").toFixed(2); // Returns 1.56 as expected.
1.3555.toFixed(3) // Returns 1.355 instead of expected 1.356.
// However, it will return correct result if you round 1.35551.
1.35551.toFixed(2); // Returns 1.36 as expected.

Ik denk dat dit komt omdat 1.555 eigenlijk zoiets is als float 1.55499994 achter de schermen.

Oplossing 1is het gebruik van een script met het vereiste afrondingsalgoritme, bijvoorbeeld:

function roundNumber(num, scale) {
  if(!("" + num).includes("e")) {
    return +(Math.round(num + "e+" + scale)  + "e-" + scale);
  } else {
    var arr = ("" + num).split("e");
    var sig = ""
    if(+arr[1] + scale > 0) {
      sig = "+";
    }
    return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale);
  }
}

https://plnkr.co/edit/uau8BlS1cqbvWPCHJeOy?p=preview

OPMERKING:dit is niet voor iedereen een universele oplossing. Er zijn verschillende afrondingsalgoritmen, uw implementatie kan verschillen, afhankelijk van uw vereisten. https://en.wikipedia.org/wiki/Rounding

Oplossing 2is om frontend-berekeningen te vermijden en afgeronde waarden van de backend-server te halen.

Bewerken:een andere mogelijke oplossing, die ook niet kogelvrij is.

Math.round((num + Number.EPSILON) * 100) / 100

In sommige gevallen, wanneer u een getal als 1.354999999999998 afrondt, krijgt u een onjuist resultaat. Zou 1,35 moeten zijn, maar het resultaat is 1,36.


Antwoord 3, autoriteit 12%

U kunt gebruiken

function roundToTwo(num) {    
    return +(Math.round(num + "e+2")  + "e-2");
}

Ik vond dit op MDN. Hun manier vermijdt het probleem met 1.005 dat genoemd.

roundToTwo(1.005)
1.01
roundToTwo(10)
10
roundToTwo(1.7777777)
1.78
roundToTwo(9.1)
9.1
roundToTwo(1234.5678)
1234.57

Antwoord 4, autoriteit 4%

MarkG’s antwoord is het juiste. Hier is een algemene extensie voor een willekeurig aantal decimalen.

Number.prototype.round = function(places) {
  return +(Math.round(this + "e+" + places)  + "e-" + places);
}

Gebruik:

var n = 1.7777;    
n.round(2); // 1.78

Eenheidstest:

it.only('should round floats to 2 places', function() {
  var cases = [
    { n: 10,      e: 10,    p:2 },
    { n: 1.7777,  e: 1.78,  p:2 },
    { n: 1.005,   e: 1.01,  p:2 },
    { n: 1.005,   e: 1,     p:0 },
    { n: 1.77777, e: 1.8,   p:1 }
  ]
  cases.forEach(function(testCase) {
    var r = testCase.n.round(testCase.p);
    assert.equal(r, testCase.e, 'didn\'t get right number');
  });
})

Antwoord 5, autoriteit 4%

U moet gebruiken:

Math.round( num * 100 + Number.EPSILON ) / 100

Niemand lijkt op de hoogte te zijn van Number.EPSILON.

Het is ook vermeldenswaard dat dit geen JavaScript-gekheidis zoals sommige mensen zeiden.

Dat is gewoon de manier waarop getallen met drijvende komma werken op een computer.Net als 99% van de programmeertalen heeft JavaScript geen zelfgemaaktegetallen met drijvende komma; daarvoor is het afhankelijk van de CPU/FPU. Een computer gebruikt binair, en in binair zijn er geen getallen zoals 0.1, maar slechts een binaire benadering daarvoor. Waarom? Om dezelfde reden kan 1/3 niet in decimalen worden geschreven: de waarde is 0,333333333… met een oneindig aantal drieën.

Hier komt Number.EPSILON. Dat getal is het verschil tussen 1 en het volgendegetal dat bestaat in de drijvende-kommagetallen met dubbele precisie. Dat is het: er is geen getal tussen 1en 1 + Number.EPSILON.

BEWERKEN:

Zoals gevraagd in de opmerkingen, laten we één ding verduidelijken: het toevoegen van Number.EPSILONis alleen relevant wanneer de af te ronden waarde het resultaat is van een rekenkundige bewerking, omdat het een zwevende-komma-foutdelta kan inslikken .

Het is niet handig als de waarde afkomstig is van een directe bron (bijvoorbeeld: letterlijk, gebruikersinvoer of sensor).

BEWERKEN (2019):

Zoals @maganap en sommige mensen hebben aangegeven, is het het beste om Number.EPSILONvóór vermenigvuldiging:

Math.round( ( num + Number.EPSILON ) * 100 ) / 100

BEWERKEN (december 2019):

De laatste tijd gebruik ik een functie die lijkt op deze om epsilon-bewust getallen te vergelijken:

const ESPILON_RATE = 1 + Number.EPSILON ;
const ESPILON_ZERO = Number.MIN_VALUE ;
function epsilonEquals( a , b ) {
  if ( Number.isNaN( a ) || Number.isNaN( b ) ) {
    return false ;
  }
  if ( a === 0 || b === 0 ) {
    return a <= b + EPSILON_ZERO && b <= a + EPSILON_ZERO ;
  }
  return a <= b * EPSILON_RATE && b <= a * EPSILON_RATE ;
}

Mijn use-case is een bewering + gegevensvalidatie-libdie ik al vele jaren aan het ontwikkelen ben .

In feite gebruik ik in de code ESPILON_RATE = 1 + 4 * Number.EPSILONen EPSILON_ZERO = 4 * Number.MIN_VALUE(vier keer de epsilon) , omdat ik een gelijkheidscontrole wil die los genoeg is om een drijvende-kommafout te cumuleren.

Tot nu toe ziet het er perfect uit voor mij.
Ik hoop dat het zal helpen.


Antwoord 6, autoriteit 2%

Deze vraag is ingewikkeld.

Stel dat we een functie hebben, roundTo2DP(num), die een float als argument neemt en een waarde teruggeeft die is afgerond op 2 decimalen. Wat moet elk van deze uitdrukkingen opleveren?

  • roundTo2DP(0.014999999999999999)
  • roundTo2DP(0.0150000000000000001)
  • roundTo2DP(0.015)

Het ‘voor de hand liggende’ antwoord is dat het eerste voorbeeld moet worden afgerond op 0,01 (omdat het dichter bij 0,01 ligt dan bij 0,02), terwijl de andere twee moeten worden afgerond op 0,02 (omdat 0,0150000000000000001 dichter bij 0,02 ligt dan bij 0,01, en omdat 0,015 gelijk is aan precies halverwege en er is een wiskundige afspraak dat zulke getallen naar boven worden afgerond).

Het addertje onder het gras, dat je misschien al geraden had, is dat roundTo2DPmogelijk nietkan worden geïmplementeerd om die voor de hand liggende antwoorden te geven, omdat alle drie de getallen die eraan worden doorgegeven zijn hetzelfde nummer. IEEE 754 binaire getallen met drijvende komma (het soort dat wordt gebruikt door JavaScript) kunnen niet precies de meeste niet-gehele getallen vertegenwoordigen, en daarom worden alle drie de letterlijke getallen hierboven afgerond naar een nabijgelegen geldig drijvende komma-getal. Dit nummer is namelijk exact

0.01499999999999999944488848768742172978818416595458984375

wat dichter bij 0,01 ligt dan bij 0,02.

Je kunt zien dat alle drie de nummers hetzelfde zijn in je browserconsole, Node-shell of een andere JavaScript-interpreter. Vergelijk ze gewoon:

> 0.014999999999999999 === 0.0150000000000000001
true

Dus als ik m = 0.0150000000000000001schrijf, ligt de exacte waarde van mdie ik krijg dichter bij 0.01dan het is naar 0.02. En toch, als ik mconverteer naar een String…

> var m = 0.0150000000000000001;
> console.log(String(m));
0.015
> var m = 0.014999999999999999;
> console.log(String(m));
0.015

… ik krijg 0,015, wat zou moeten afronden op 0,02, en dat is opvallend niethet getal van 56 decimalen waar ik eerder zei dat al deze getallen precies gelijk waren aan. Dus welke duistere magie is dit?

Het antwoord is te vinden in de ECMAScript-specificatie, in sectie 7.1.12.1: ToString toegepast op het nummertype. Hier worden de regels vastgelegd voor het converteren van een getal mnaar een String. Het belangrijkste onderdeel is punt 5, waarin een geheel getal swordt gegenereerd waarvan de cijfers zullen worden gebruikt in de tekenreeksrepresentatie van m:

laat n, ken sgehele getallen zijn zodat k≥ 1, 10k-1s< 10k, de Getalwaarde voor s× 10nkis men kis zo klein mogelijk. Merk op dat k het aantal cijfers is in de decimale representatie van s, dat sniet deelbaar is door 10, en dat het minst significante cijfer van sem>wordt niet noodzakelijk uniek bepaald door deze criteria.

Het belangrijkste hier is de eis dat “kzo klein mogelijk is”. Die eis komt neer op een eis dat, gegeven een Getal m, de waarde van String(m)het minst mogelijke aantal cijfersterwijl het nog steeds voldoet aan de eis dat Number(String(m)) === m. Omdat we al weten dat 0.015 === 0.0150000000000000001, is het nu duidelijk waarom String(0.0150000000000000001) === '0.015'waar moet zijn.

Natuurlijk heeft geen van deze discussies direct antwoord gegeven op wat roundTo2DP(m)moetteruggeven. Als de exacte waarde van m0,01499999999999999944488878768742172978818416595458984375 is, maar de tekenreeksrepresentatie is ‘0,015’, wat is dan het juisteantwoord – wiskundig, praktisch, filosofisch of wat dan ook – als we afronden op twee decimalen?

Er is niet één juist antwoord hierop. Het hangt af van uw gebruiksscenario. U wilt waarschijnlijk de tekenreeksweergave respecteren en naar boven afronden wanneer:

  • De weergegeven waarde is inherent discreet, b.v. een hoeveelheid valuta in een valuta met drie decimalen, zoals dinars. In dit geval is de warewaarde van een getal zoals 0,015 is0,015, en de 0,0149999999… weergave die het in binaire drijvende komma krijgt, is een afrondingsfout. (Natuurlijk zullen velen redelijkerwijs beweren dat je een decimale bibliotheek moet gebruiken om dergelijke waarden te verwerken en ze in de eerste plaats nooit als binaire getallen met drijvende komma moet voorstellen.)
  • De waarde is getypt door een gebruiker. Ook in dit geval is het exacte decimale getal dat is ingevoerd meer ‘waar’ dan de dichtstbijzijnde binaire drijvende-kommaweergave.

Aan de andere kant wilt u waarschijnlijk de binaire drijvende-kommawaarde respecteren en naar beneden afronden wanneer uw waarde van een inherent continue schaal is, bijvoorbeeld als het een meting van een sensor is.

Deze twee benaderingen vereisen verschillende code. Om de tekenreeksrepresentatie van het getal te respecteren, kunnen we (met nogal wat redelijk subtiele code) onze eigen afronding implementeren die direct op de tekenreeksrepresentatie inwerkt, cijfer voor cijfer, met hetzelfde algoritme dat u op school zou hebben gebruikt als u leerden getallen af te ronden. Hieronder ziet u een voorbeeld dat voldoet aan de eis van het OP om het getal tot op 2 decimalen “alleen indien nodig” weer te geven door de nullen achter de komma te verwijderen; het kan natuurlijk nodig zijn om het aan uw specifieke behoeften aan te passen.

/**
 * Converts num to a decimal string (if it isn't one already) and then rounds it
 * to at most dp decimal places.
 *
 * For explanation of why you'd want to perform rounding operations on a String
 * rather than a Number, see http://stackoverflow.com/a/38676273/1709587
 *
 * @param {(number|string)} num
 * @param {number} dp
 * @return {string}
 */
function roundStringNumberWithoutTrailingZeroes (num, dp) {
    if (arguments.length != 2) throw new Error("2 arguments required");
    num = String(num);
    if (num.indexOf('e+') != -1) {
        // Can't round numbers this large because their string representation
        // contains an exponent, like 9.99e+37
        throw new Error("num too large");
    }
    if (num.indexOf('.') == -1) {
        // Nothing to do
        return num;
    }
    var parts = num.split('.'),
        beforePoint = parts[0],
        afterPoint = parts[1],
        shouldRoundUp = afterPoint[dp] >= 5,
        finalNumber;
    afterPoint = afterPoint.slice(0, dp);
    if (!shouldRoundUp) {
        finalNumber = beforePoint + '.' + afterPoint;
    } else if (/^9+$/.test(afterPoint)) {
        // If we need to round up a number like 1.9999, increment the integer
        // before the decimal point and discard the fractional part.
        finalNumber = Number(beforePoint)+1;
    } else {
        // Starting from the last digit, increment digits until we find one
        // that is not 9, then stop
        var i = dp-1;
        while (true) {
            if (afterPoint[i] == '9') {
                afterPoint = afterPoint.substr(0, i) +
                             '0' +
                             afterPoint.substr(i+1);
                i--;
            } else {
                afterPoint = afterPoint.substr(0, i) +
                             (Number(afterPoint[i]) + 1) +
                             afterPoint.substr(i+1);
                break;
            }
        }
        finalNumber = beforePoint + '.' + afterPoint;
    }
    // Remove trailing zeroes from fractional part before returning
    return finalNumber.replace(/0+$/, '')
}

Voorbeeld van gebruik:

> roundStringNumberWithoutTrailingZeroes(1.6, 2)
'1.6'
> roundStringNumberWithoutTrailingZeroes(10000, 2)
'10000'
> roundStringNumberWithoutTrailingZeroes(0.015, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.015000', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(1, 1)
'1'
> roundStringNumberWithoutTrailingZeroes('0.015', 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes(0.01499999999999999944488848768742172978818416595458984375, 2)
'0.02'
> roundStringNumberWithoutTrailingZeroes('0.01499999999999999944488848768742172978818416595458984375', 2)
'0.01'

De bovenstaande functie is waarschijnlijkwat u wilt gebruiken om te voorkomen dat gebruikers ooit zien dat getallen die ze hebben ingevoerd verkeerd worden afgerond.

(Als alternatief kunt u ook de bibliotheek round10proberen, die een vergelijkbare functie biedt met een totaal andere implementatie.)

Maar wat als je het tweede soort Getal hebt – een waarde die is genomen van een continue schaal, waarbij er geen reden is om aan te nemen dat benaderde decimale representaties met minder decimalen nauwkeurigerzijn dan die met meer ? In dat geval willen we nietde String-representatie respecteren, omdat die representatie (zoals uitgelegd in de specificatie) al min of meer afgerond is; we willen niet de fout maken om te zeggen “0.014999999…375 rondt af op 0,015, wat afrondt op 0,02, dus 0,014999999…375 rondt af op 0,02”.

Hier kunnen we eenvoudig de ingebouwde toFixedmethode. Merk op dat door Number()aan te roepen op de tekenreeks die wordt geretourneerd door toFixed, we een getal krijgen waarvan de tekenreeksrepresentatie geen nullen heeft (dankzij de manier waarop JavaScript de tekenreeksrepresentatie berekent van een nummer, eerder in dit antwoord besproken).

/**
 * Takes a float and rounds it to at most dp decimal places. For example
 *
 *     roundFloatNumberWithoutTrailingZeroes(1.2345, 3)
 *
 * returns 1.234
 *
 * Note that since this treats the value passed to it as a floating point
 * number, it will have counterintuitive results in some cases. For instance,
 * 
 *     roundFloatNumberWithoutTrailingZeroes(0.015, 2)
 *
 * gives 0.01 where 0.02 might be expected. For an explanation of why, see
 * http://stackoverflow.com/a/38676273/1709587. You may want to consider using the
 * roundStringNumberWithoutTrailingZeroes function there instead.
 *
 * @param {number} num
 * @param {number} dp
 * @return {number}
 */
function roundFloatNumberWithoutTrailingZeroes (num, dp) {
    var numToFixedDp = Number(num).toFixed(dp);
    return Number(numToFixedDp);
}

Antwoord 7, autoriteit 2%

Overweeg .toFixed()en .toPrecision():

http://www.javascriptkit.com/javatutors/formatnumber.shtml


Antwoord 8, autoriteit 2%

Men kan .toFixed(NumberOfDecimalPlaces)gebruiken.

var str = 10.234.toFixed(2); // => '10.23'
var number = Number(str); // => 10.23

Antwoord 9, autoriteit 2%

Over het algemeen wordt decimale afronding gedaan door te schalen: round(num * p) / p

Naïeve implementatie

Als u de volgende functie gebruikt met halve cijfers, krijgt u ofwel de bovenste afgeronde waarde zoals verwacht, of de lagere afgeronde waarde, soms afhankelijk van de invoer.

Deze inconsistencyin afronding kan leiden tot moeilijk te detecteren bugs in de klantcode.

function naiveRound(num, decimalPlaces = 0) {
    var p = Math.pow(10, decimalPlaces);
    return Math.round(num * p) / p;
}
console.log( naiveRound(1.245, 2) );  // 1.25 correct (rounded as expected)
console.log( naiveRound(1.255, 2) );  // 1.25 incorrect (should be 1.26)
// testing edge cases
console.log( naiveRound(1.005, 2) );  // 1    incorrect (should be 1.01)
console.log( naiveRound(2.175, 2) );  // 2.17 incorrect (should be 2.18)
console.log( naiveRound(5.015, 2) );  // 5.01 incorrect (should be 5.02)

Antwoord 10

Een nauwkeurige afrondingsmethode. Bron: Mozilla

(function(){
    /**
     * Decimal adjustment of a number.
     *
     * @param   {String}    type    The type of adjustment.
     * @param   {Number}    value   The number.
     * @param   {Integer}   exp     The exponent (the 10 logarithm of the adjustment base).
     * @returns {Number}            The adjusted value.
     */
    function decimalAdjust(type, value, exp) {
        // If the exp is undefined or zero...
        if (typeof exp === 'undefined' || +exp === 0) {
            return Math[type](value);
        }
        value = +value;
        exp = +exp;
        // If the value is not a number or the exp is not an integer...
        if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) {
            return NaN;
        }
        // Shift
        value = value.toString().split('e');
        value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp)));
        // Shift back
        value = value.toString().split('e');
        return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp));
    }
    // Decimal round
    if (!Math.round10) {
        Math.round10 = function(value, exp) {
            return decimalAdjust('round', value, exp);
        };
    }
    // Decimal floor
    if (!Math.floor10) {
        Math.floor10 = function(value, exp) {
            return decimalAdjust('floor', value, exp);
        };
    }
    // Decimal ceil
    if (!Math.ceil10) {
        Math.ceil10 = function(value, exp) {
            return decimalAdjust('ceil', value, exp);
        };
    }
})();

Voorbeelden:

// Round
Math.round10(55.55, -1); // 55.6
Math.round10(55.549, -1); // 55.5
Math.round10(55, 1); // 60
Math.round10(54.9, 1); // 50
Math.round10(-55.55, -1); // -55.5
Math.round10(-55.551, -1); // -55.6
Math.round10(-55, 1); // -50
Math.round10(-55.1, 1); // -60
Math.round10(1.005, -2); // 1.01 -- compare this with Math.round(1.005*100)/100 above
// Floor
Math.floor10(55.59, -1); // 55.5
Math.floor10(59, 1); // 50
Math.floor10(-55.51, -1); // -55.6
Math.floor10(-51, 1); // -60
// Ceil
Math.ceil10(55.51, -1); // 55.6
Math.ceil10(51, 1); // 60
Math.ceil10(-55.59, -1); // -55.5
Math.ceil10(-59, 1); // -50

Antwoord 11

Geen van de hier gevonden antwoorden is correct. @stinkycheeseman vroeg om naar boven af te ronden, jullie hebben allemaal het getal afgerond.

Gebruik dit om naar boven af te ronden:

Math.ceil(num * 100)/100;

Antwoord 12

Hier is een eenvoudige manier om het te doen:

Math.round(value * 100) / 100

Misschien wilt u doorgaan en een aparte functie maken om het voor u te doen:

function roundToTwo(value) {
    return(Math.round(value * 100) / 100);
}

Dan geef je gewoon de waarde door.

Je zou het kunnen verbeteren om af te ronden op een willekeurig aantal decimalen door een tweede parameter toe te voegen.

function myRound(value, places) {
    var multiplier = Math.pow(10, places);
    return (Math.round(value * multiplier) / multiplier);
}

Antwoord 13

+(10).toFixed(2); // = 10
+(10.12345).toFixed(2); // = 10.12
(10).toFixed(2); // = 10.00
(10.12345).toFixed(2); // = 10.12

Antwoord 14

Voor mij Math.round()gaf niet het juiste antwoord. Ik heb gevonden dat toFixed(2)werkt beter.
Hieronder staan voorbeelden van beide:

console.log(Math.round(43000 / 80000) * 100); // wrong answer
console.log(((43000 / 80000) * 100).toFixed(2)); // correct answer

Antwoord 15

Gebruik deze functie Number(x).toFixed(2);


Antwoord 16

Probeer deze lichtgewichtoplossing:

function round(x, digits){
  return parseFloat(x.toFixed(digits))
}
 round(1.222,  2) ;
 // 1.22
 round(1.222, 10) ;
 // 1.222

Antwoord 17

2017
Gebruik gewoon native code .toFixed()

number = 1.2345;
number.toFixed(2) // "1.23"

Als je streng moet zijn en alleen cijfers moet toevoegen als dat nodig is, kun je replace

gebruiken

number = 1; // "1"
number.toFixed(5).replace(/\.?0*$/g,'');

Antwoord 18

Er zijn een aantal manieren om dat te doen. Voor mensen zoals ik, de variant van Lodash

function round(number, precision) {
    var pair = (number + 'e').split('e')
    var value = Math.round(pair[0] + 'e' + (+pair[1] + precision))
    pair = (value + 'e').split('e')
    return +(pair[0] + 'e' + (+pair[1] - precision))
}

Gebruik:

round(0.015, 2) // 0.02
round(1.005, 2) // 1.01

Als uw project jQuery of lodash gebruikt, kunt u in de bibliotheken ook de juiste round-methode vinden.

Update 1

Ik heb de variant n.toFixed(2)verwijderd, omdat deze niet correct is. Bedankt @avalanche1


Antwoord 19

Dit kan je helpen:

var result = Math.round(input*100)/100;

voor meer informatie kun je deze link bekijken

Math.round(num) vs num. toFixed(0) en inconsistenties in de browser


Antwoord 20

Als je de lodash-bibliotheek gebruikt, kun je de ronde methode van lodash gebruiken, zoals de volgende.

_.round(number, precision)

Bijvoorbeeld:

_.round(1.7777777, 2) = 1.78

Antwoord 21

Sinds ES6 is er een ‘juiste’ manier (zonder statica te negeren en tijdelijke oplossingen te creëren) om dit te doen door toPrecision gebruiken

var x = 1.49999999999;
console.log(x.toPrecision(4));
console.log(x.toPrecision(3));
console.log(x.toPrecision(2));
var y = Math.PI;
console.log(y.toPrecision(6));
console.log(y.toPrecision(5));
console.log(y.toPrecision(4));
var z = 222.987654
console.log(z.toPrecision(6));
console.log(z.toPrecision(5));
console.log(z.toPrecision(4));

Antwoord 22

De eenvoudigste benadering zou zijn om toFixed te gebruiken en vervolgens de nullen te verwijderen met de functie Getal:

const number = 15.5;
Number(number.toFixed(2)); // 15.5
const number = 1.7777777;
Number(number.toFixed(2)); // 1.78

Antwoord 23

MarkG en Lavamantis boden een veel betere oplossing dan de geaccepteerde. Het is jammer dat ze niet meer stemmen krijgen!

Hier is de functie die ik gebruik om de problemen met drijvende komma’s op te lossen ook gebaseerd op MDN. Het is zelfs algemener (maar minder beknopt) dan de oplossing van Lavamantis:

function round(value, exp) {
  if (typeof exp === 'undefined' || +exp === 0)
    return Math.round(value);
  value = +value;
  exp  = +exp;
  if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
    return NaN;
  // Shift
  value = value.toString().split('e');
  value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
  // Shift back
  value = value.toString().split('e');
  return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}

Gebruik het met:

round(10.8034, 2);      // Returns 10.8
round(1.275, 2);        // Returns 1.28
round(1.27499, 2);      // Returns 1.27
round(1.2345678e+2, 2); // Returns 123.46

Vergeleken met de oplossing van Lavamantis kunnen we…

round(1234.5678, -2); // Returns 1200
round("123.45");      // Returns 123

Antwoord 24

Het kan voor u werken,

Math.round(num * 100)/100;

om het verschil te weten tussen toFixed en round. U kunt een kijkje nemen op Math.round (num) vs num.toFixed(0) en inconsistenties in de browser.


Antwoord 25

var roundUpto = function(number, upto){
    return Number(number.toFixed(upto));
}
roundUpto(0.1464676, 2);

toFixed(2)hier is 2 het aantal cijfers waarop we dit getal willen afronden.


Antwoord 26

Een manier om een dergelijke afronding alleen indien nodigte realiseren, is door Number.prototype.toLocaleString():

myNumber.toLocaleString('en', {maximumFractionDigits:2, useGrouping:false})

Dit geeft precies de output die je verwacht, maar dan als strings. Je kunt die nog steeds terug converteren naar getallen als dat niet het gegevenstype is dat je verwacht.


Antwoord 27

DEFINITIEVE UPDATE:

Ik laat dit antwoord hier voor het nageslacht, maar ik zou aanraden om @AmrAli’s aanpassing van de DecimalPrecision-functie te gebruiken, omdat deze ook is uitgerust om exponentiële notatie te verwerken. Ik had oorspronkelijk geprobeerd om elke vorm van stringconversie/manipulatie om prestatieredenen te vermijden, maar er is vrijwel geen verschil in prestatie met zijn implementatie.

EDIT 22-8-2020: Ik denk dat hier moet worden verduidelijkt dat het doel van deze inspanningen niet is om de inherente afrondingsfouten die worden veroorzaakt door het gegevenstype met drijvende komma volledig te elimineren, aangezien dat nooit mogelijk zal zijn zonder over te schakelen naar een gegevenstype dat de waarde feitelijk opslaat als een base10 (decimaal). Het doel zou eigenlijk moeten zijn om de onnauwkeurigheden zo ver mogelijk naar de rand te duwen, zodat je wiskundige bewerkingen op een bepaalde waarde kunt uitvoeren zonder de bug te produceren. Op het moment dat uw waarde de absolute rand bereikt, waarbij het eenvoudig aanroepen van de waarde ervoor zou zorgen dat JS de bug zou produceren, vóór of nadat u deze hebt gemanipuleerd, kunt u niets meer doen om dat te verhelpen. Als u bijvoorbeeld de waarde 0,014999999999999999 instantieert, rondt JS deze onmiddellijk af op 0,015. Dus als je die waarde aan een van deze functies hebt doorgegeven, geef je eigenlijk 0,015 door. Op dat moment kon je niet eens eerst converteren naar string en het dan manipuleren, de waarde zou vanaf het begin als een string moeten worden geïnstantieerd om dat te laten werken. Het doel, en enige redelijke verwachting, van alle functies die zijn gemaakt om deze bug te verhelpen, is eenvoudigweg om wiskundige bewerkingen uit te voeren op drijvende-kommawaarden terwijl de bug helemaal naar de rand wordt geduwd waar ofwel de startwaarde of de resulterende waarde de bug zou produceren door simpelweg toch te worden aangeroepen. De enige andere alternatieve oplossing zou zijn om de gehele getallen en decimale waarden onafhankelijk op te slaan, beide als gehele getallen, zodat ze alleen als zodanig worden aangeroepen, of om de waarde altijd als een string op te slaan en een combinatie te gebruiken van stringmanipulatie en op integers gebaseerde wiskunde om er bewerkingen op uit te voeren.

Na het doorlopen van verschillende iteraties van alle mogelijke manieren om echt nauwkeurige decimale afrondingsprecisie te bereiken, is het duidelijk dat de meest nauwkeurige en efficiënte oplossing het gebruik van Number.EPSILON is. Dit biedt een echte wiskundige oplossing voor het probleem van wiskundige precisie met drijvende komma. Het kan eenvoudig worden gepolyfilleerd zoals hier wordt getoond: https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILONom alle laatst overgebleven IE-gebruikers te ondersteunen (maar misschien moeten we daar ook mee stoppen).

Aangepast van de oplossing die hier wordt geboden: https://stackoverflow.com/a/48850944/6910392

Een eenvoudige drop-in-oplossing die nauwkeurige decimale afrondingen, vloeren en plafonds biedt, met een optionele precisievariabele zonder een hele bibliotheek toe te voegen.

05-19-2020 UPDATE: Zoals Sergey opmerkte in de opmerkingen, is er een beperking aan deze (of enige) methode die het vermelden waard is. In het geval van getallen zoals 0.014999999999999999, zult u nog steeds onnauwkeurigheden ervaren die het gevolg zijn van het bereiken van de absolute rand van nauwkeurigheidsbeperkingen voor opslag van drijvende-kommawaarden. Er is geen wiskundige of andere oplossing die hiervoor kan worden toegepast, omdat de waarde zelf onmiddellijk wordt geëvalueerd als 0,015. U kunt dit bevestigen door die waarde eenvoudig zelf in de console aan te roepen. Vanwege deze beperking zou het niet eens mogelijk zijn om stringmanipulatie te gebruiken om deze waarde te verminderen, omdat de stringweergave gewoon “0.015” is. Elke oplossing om hiermee rekening te houden zou logisch moeten worden toegepast bij de bron van de gegevens voordat de waarde ooit in een script wordt geaccepteerd, bijvoorbeeld door de tekenlengte van een veld te beperken, enz. Dat zou een overweging zijn waarmee rekening moet worden gehouden per geval om de beste aanpak te bepalen.

08-19-2020 UPDATE: Volgens de opmerking van Amr zullen de ceil- en floor-functies ongewenste resultaten opleveren als de invoerwaarde een geheel getal is. Dit komt door de toevoeging die is toegepast op de invoer met Number.EPSILON om de verwachte float-onnauwkeurigheid te compenseren. De functie is bijgewerkt om te controleren of de invoerwaarde een geheel getal is en de waarde ongewijzigd terug te geven, aangezien dat het juiste resultaat is van beide functies wanneer toegepast op een geheel getal.

*Opmerking: dit probleem onthult ook dat, hoewel de ceil- en floor-functies nog steeds de toepassing van de Number.EPSILON-aanpassing vereisen, ze ongewenste resultaten opleveren wanneer ze worden toegepast op een waarde waarbij het aantal decimalen in het invoergetal lager is dan het aantal decimalen dat wordt gevraagd voor de uitvoer (p). ceil(17.1, 5) zou bijvoorbeeld 17.1 moeten retourneren in relatie tot het verwachte “ceil”-functiegedrag wanneer toegepast op gehele getallen in de wiskunde, waarbij wordt aangenomen dat alle decimalen na “1” 0 zijn. Om hiervoor te corrigeren, I’ We hebben een extra functiecontrole toegevoegd om vast te stellen of het aantal decimalen in het invoergetal lager is dan de gevraagde uitvoerdecimaaltekens, en het getal ongewijzigd terug te geven, net als bij hele getallen.

var DecimalPrecision = (function(){
        if (Number.EPSILON === undefined) {
            Number.EPSILON = Math.pow(2, -52);
        }
        if(Number.isInteger === undefined){
            Number.isInteger = function(value) {
                return typeof value === 'number' && 
                isFinite(value) && 
                Math.floor(value) === value;
            };
        }
        this.isRound = function(n,p){
            let l = n.toString().split('.')[1].length;
            return (p >= l);
        }
        this.round = function(n, p=2){
            if(Number.isInteger(n) || this.isRound(n,p))
                return n;
            let r = 0.5 * Number.EPSILON * n;
            let o = 1; while(p-- > 0) o *= 10;
            if(n<0)
                o *= -1;
            return Math.round((n + r) * o) / o;
        }
        this.ceil = function(n, p=2){
            if(Number.isInteger(n) || this.isRound(n,p))
                return n;
            let r = 0.5 * Number.EPSILON * n;
            let o = 1; while(p-- > 0) o *= 10;
            return Math.ceil((n + r) * o) / o;
        }
        this.floor = function(n, p=2){
            if(Number.isInteger(n) || this.isRound(n,p))
                return n;
            let r = 0.5 * Number.EPSILON * n;
            let o = 1; while(p-- > 0) o *= 10;
            return Math.floor((n + r) * o) / o;
        }
        return this;
    })();
    console.log(DecimalPrecision.round(1.005));
    console.log(DecimalPrecision.ceil(1.005));
    console.log(DecimalPrecision.floor(1.005));
    console.log(DecimalPrecision.round(1.0049999));
    console.log(DecimalPrecision.ceil(1.0049999));
    console.log(DecimalPrecision.floor(1.0049999));
    console.log(DecimalPrecision.round(2.175495134384,7));
    console.log(DecimalPrecision.round(2.1753543549,8));
    console.log(DecimalPrecision.round(2.1755465135353,4));
    console.log(DecimalPrecision.ceil(17,4));
    console.log(DecimalPrecision.ceil(17.1,4));
    console.log(DecimalPrecision.ceil(17.1,15));

Antwoord 28

Gemakkelijkste manier:

+num.toFixed(2)

Het converteert het naar een string, en dan terug naar een geheel getal / float.


Antwoord 29

Hier is een prototypemethode:

Number.prototype.round = function(places){
    places = Math.pow(10, places); 
    return Math.round(this * places)/places;
}
var yournum = 10.55555;
yournum = yournum.round(2);

Antwoord 30

Gebruik deze variant om niet met veel nullen om te gaan:

Math.round(num * 1e2) / 1e2

Other episodes