JavaScript'te bir sayıyı nasıl yuvarlayabilirim? .toFixed () bir dize döndürür?


176

Burada bir şey mi eksik?

var someNumber = 123.456;
someNumber = someNumber.toFixed(2);
alert(typeof(someNumber));
//alerts string

Neden gelmez.toFixed()bir dize döndürür?

Sayıyı 2 ondalık basamağa yuvarlamak istiyorum.


7
Bir dize döndürmek için tasarlanmış olduğundan?
kennytm

2
Bana göre bu tuhaf görünüyor. .toFixed () yalnızca sayılarda çalışır ... değil mi?
Derek Adair

10
Math.round () işlevinin beklendiği gibi çalıştığını anlıyorum. Sadece sayılar üzerinde çalışan bir fonksiyonun neden bir dize döndürdüğünü soruyordum ...
Derek Adair

3
2017 yılında yaşayan insanlar gibi kütüphaneleri kullanmalıdır lodash.com/docs/4.17.4#ceil
Yves M.

1
_ De öyle. Miktar? henüz kardeşine geçmedi.
Jenna Leaf

Yanıtlar:


124

Bir dize döndürür, çünkü 0.1 ve güçleri (ondalık kesirleri görüntülemek için kullanılır), ikili kayan noktalı sistemlerde temsil edilemez (en azından tam doğrulukla değil).

Örneğin, 0.1 gerçekten 0.1000000000000000055511151231257827021181583404541015625 ve 0.01 gerçekten 0.01000000000000000020816681711721685132943093776702880859375. (Demek istediğimi BigDecimalkanıtladığın için teşekkürler . :-P)

Bu nedenle (ondalık kayan nokta veya rasyonel sayı türü olmadığında), dize olarak çıktı almak, görüntüleme için gereken hassasiyete göre kesilmesinin tek yoludur.


28
en azından javascript bana biraz parmak işi kurtarabilir ve bir sayıya dönüştürebilir ... sheesh ...
Derek Adair

10
@Derek: Evet, ama tekrar bir sayıya dönüştürdüğünüzde, yine aynı yanlışlık sorunlarıyla karşılaşıyorsunuz. :-P JS ondalık kayan nokta veya rasyonel sayı içermiyor.
Chris Jester-Young

1
@DerekAdair Yakın zamanda bunu daha da açıklayan, ilginizi çekebilecek bir yazı yazdım. Keyfini çıkarın! stackoverflow.com/a/27030789/13
Chris Jester-Young

7
Aslında bu, bu konuda oldukça ağır araştırmalar yapmama neden oldu! Yardımların için teşekkür ederim!
Derek Adair

2
Cevabınız biraz yanıltıcı: toFixedsadece bir sayıyı bir dizeye dönüştürmek, belirtilen ondalık sayıları kullanarak biçimlendirmek olan bir biçimlendirme işlevidir. Bir dize döndürmesinin nedeni, bir dize döndürmesi gerektiğidir ve toStringFixedbunun yerine adlandırılırsa , OP sonuçlara şaşırmaz. Buradaki tek sorun OP'nin Math.roundJS referansına başvurmadan çalışmasını beklemesidir .
Groo

177

Number.prototype.toFixedbir sayıyı yazdırmadan önce biçimlendirmek için tasarlanmış bir işlevdir . Bu bir aileden geliyor toString, toExponentialve toPrecision.

Bir sayıyı yuvarlamak için bunu yaparsınız:

someNumber = 42.008;
someNumber = Math.round( someNumber * 1e2 ) / 1e2;
someNumber === 42.01;

// if you need 3 digits, replace 1e2 with 1e3 etc.
// or just copypaste this function to your code:

function toFixedNumber(num, digits, base){
  var pow = Math.pow(base||10, digits);
  return Math.round(num*pow) / pow;
}

.

Veya " yerel benzeri " bir işlev istiyorsanız, prototipi genişletebilirsiniz:

Number.prototype.toFixedNumber = function(digits, base){
  var pow = Math.pow(base||10, digits);
  return Math.round(this*pow) / pow;
}
someNumber = 42.008;
someNumber = someNumber.toFixedNumber(2);
someNumber === 42.01;


//or even hexadecimal

someNumber = 0xAF309/256  //which is af3.09
someNumber = someNumber.toFixedNumber(1, 16);
someNumber.toString(16) === "af3.1";

Bununla birlikte , modül yazarken prototipi kirletmenin kötü kabul edildiğini unutmayın, çünkü modüllerin herhangi bir yan etkisi olmamalıdır. Bu nedenle, bir modül için ilk işlevi kullanın .


12
Bence bu en iyi cevap. Tür dönüşümünü önler. Muhteşem sos!
Phil

1
Mükemmel cevap! Ancak ... 20 yıldır JavaScript yapıyorum ama neden + (...) yapısını geri dönüş değerinin etrafında kullandığınızı anlayamıyorum? Sürtüğünüz için teşekkürler @sam :) Öğrenmek için çok yaşlı olmadığım için lütfen ayrıntılı :-)
HammerNL

1
@HammerNL Sam'in mahkumiyetine rağmen, hiçbir şey yapmaz :) Bu sadece bir uygulamadır - IDE'lerin bu işlevi tanımasını sağlar type Number. Mesele şu ki, +(anyValue)her zaman bir sayı döndürür - örn. +("45")döner 45, +(new Number(42))döner 42. Bu güçlü yazma fonksiyonu gibi. Eğer bir alışkanlık yaparsanız, bir çok hata önleyebilirsiniz :)
m93a

Bu neden çekirdek javascript'e dönüştürülmüyor: s
webmaster

2
Bir resuIt someNumber = Math.round( 42.008 * 1e2 ) / 1e2;değil 42.01, öyle ~42.0099999999999980. Sebep: Sayı 42.01mevcut değil ve mevcut en yakın sayıya yuvarlanıyor. btw, toPrecision(18)ilgili tüm rakamlarla yazdırmak için rakamları onaylayın.
Wiimm

118

Bunu değiştirerek bu sorunu çözdüm:

someNumber = someNumber.toFixed(2)

...buna:

someNumber = +someNumber.toFixed(2);

Bununla birlikte, bu sayı bir dizgiye dönüştürülür ve tekrar ayrıştırılır, bu da performans üzerinde önemli bir etkisi olacaktır. Performans veya tip güvenliği ile ilgileniyorsanız, diğer cevapları da kontrol edin.


39
Hayır hayır Hayır Hayır Hayır! Yapma bunu! Sayı-string dönüşüm sadece yuvarlak çok kötü bir uygulamadır ! Bunun yerine someNumber = Math.round(someNumber * 1e2) / 1e2! Daha genel bir yol için cevabımı görün.
m93a

@ m93a - neden bu kadar kötü bir uygulama?
jczaplew

3
@jczaplew Çünkü bu şekilde yaparsanız, 32bit ikili sayı, her lanet olası ondalık basamak için 16 bit kullanılarak bir dizeye dönüştürülür ! (Bu arada, sayıları UTF-16'da depolamak, gitmek için en uygun şey değildir.) Ve dize 32 bit kayan nokta numarasına geri dönüştürülür. Rakam basamak. (Doğru ayrıştırma algoritmasını seçmek için daha önce yapılması gereken tüm testleri göz ardı edersem.) Ve tüm bunları boşuna düşünerek float üzerinde 3 hızlı işlem kullanarak yapabilirsiniz.
m93a

2
@ m93a performans nedenlerinden dolayı? bunun performansta gözle görülür bir etkisi var mı?
Sebastianb

2
@jczaplew, çünkü Dizeler (1) pratik olarak yavaş ve (2) teorik olarak yanlıştır.
Pacerier

29

Neden kullanmıyorsunuz parseFloat?

var someNumber = 123.456;
someNumber = parseFloat(someNumber.toFixed(2));
alert(typeof(someNumber));
//alerts number

15

JavaScript'in Number()fonksiyonunu kullanarak tekrar sayıya dönüştürerek çözdüm

var x = 2.2873424;
x = Number(x.toFixed(2));

12

Tabii ki bir dize döndürür. Sayısal değişkeni yuvarlamak isterseniz bunun yerine Math.round () yöntemini kullanırsınız. ToFixed, sayıyı kullanıcıya gösterilecek sabit sayıda ondalık basamakla biçimlendirmektir .


4

Sonucu bir sayıya dönüştürmek için sadece bir '+' kullanabilirsiniz.

var x = 22.032423;
x = +x.toFixed(2); // x = 22.03

3

Bir sayıyı biçimlendirmesi gerektiğinde ne dönmesini beklersiniz? Eğer bir numaranız varsa, onunla bir şey yapamazsınız çünkü örneğin 2 == 2.0 == 2.00vb.


3

Neden dize olması gerektiğine ilişkin bir örnek vermek için:

1.toFixed (2) 'yi biçimlendirirseniz' 1.00 'alırsınız.

Bu 1 ile aynı değildir, çünkü 1'de 2 ondalık sayı yoktur.


JavaScript'in tam olarak bir performans dili olmadığını biliyorum , ancak böyle bir şey kullanırsanız bir yuvarlama için daha iyi performans elde edersiniz: roundedValue = Math.round (değer * 100) * 0.01


2

Birincil kullanımı sayıları gösterdiği için mi? Sayıları yuvarlamak istiyorsanız, Math.round()uygun faktörlerle kullanın .


ancak NUMBERS gösteriyor, bu yüzden bir "sayı" döndürmemeli mi?
Derek Adair

3
@Derek: Sadece '42'bir sayı olduğu gibi ... öyle değil. Bir dizenin yalnızca rakam içerdiği için onu bir sayı yapmaz. Bu PHP değil. :-P
Chris Jester-Young

lol. Sayı içeren bir dize değil ... Bir yönteme geçirilen bir sayı. Yöntem bir sayı alır ve bir dize döndürür.
Derek Adair

@DerekAdair sağ ama bir tarayıcı Sayı görüntüleyemiyor, dizeleri ve dolayısıyla dönüşümü gösteriyor.
Nick M

1

İşte verilen cevabın biraz daha işlevsel bir versiyonu m93a.

const toFixedNumber = (toFixTo = 2, base = 10) => num => {
  const pow = Math.pow(base, toFixTo)
  return +(Math.round(num * pow) / pow)
}

const oneNumber = 10.12323223

const result1 = toFixedNumber(2)(oneNumber) // 10.12
const result2 = toFixedNumber(3)(oneNumber) // 10.123

// or using pipeline-operator
const result3 = oneNumber |> toFixedNumber(2) // 10.12

kullanışlı bir işlev, tanımlanmamış türü için çalışmıyor, bu durumda kod ekledim; if (num! == tanımsız) {return + (Math.round (num * pow) / pow)} else {return 0; }
Dino Liu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.